diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4329b12e51..7714f518d8 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -396,6 +396,8 @@ PRIVATE calls/calls_video_bubble.h calls/calls_video_incoming.cpp calls/calls_video_incoming.h + calls/calls_window.cpp + calls/calls_window.h chat_helpers/compose/compose_features.h chat_helpers/compose/compose_show.cpp chat_helpers/compose/compose_show.h diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 71f5e3ef49..22ee39de43 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4955,7 +4955,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_confcall_invite_fail_user" = "Couldn't call {user} to join."; "lng_confcall_invite_fail_many#one" = "Couldn't call **{count} person** to join."; "lng_confcall_invite_fail_many#other" = "Couldn't call **{count} people** to join."; -"lng_confcall_invite_kicked_user" = "{user} was removed from the call."; +"lng_confcall_invite_kicked_user" = "{user} was banned from the call."; "lng_confcall_invite_kicked_many#one" = "**{count} person** was removed from the call."; "lng_confcall_invite_kicked_many#other" = "**{count} people** were removed from the call."; "lng_confcall_not_accessible" = "This call is no longer accessible."; diff --git a/Telegram/SourceFiles/calls/calls_box_controller.h b/Telegram/SourceFiles/calls/calls_box_controller.h index 860839cdf2..05b943b607 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.h +++ b/Telegram/SourceFiles/calls/calls_box_controller.h @@ -20,7 +20,7 @@ namespace GroupCalls { class ListController : public PeerListController { public: - explicit ListController(not_null window); + explicit ListController(not_null<::Window::SessionController*> window); [[nodiscard]] rpl::producer shownValue() const; @@ -30,7 +30,7 @@ public: void rowRightActionClicked(not_null row) override; private: - const not_null _window; + const not_null<::Window::SessionController*> _window; base::flat_map> _groupCalls; rpl::variable _fullCount; @@ -40,7 +40,7 @@ private: class BoxController : public PeerListController { public: - explicit BoxController(not_null window); + explicit BoxController(not_null<::Window::SessionController*> window); Main::Session &session() const override; void prepare() override; @@ -68,7 +68,7 @@ private: std::unique_ptr createRow( not_null item) const; - const not_null _window; + const not_null<::Window::SessionController*> _window; MTP::Sender _api; MsgId _offsetId = 0; @@ -79,6 +79,6 @@ private: void ClearCallsBox( not_null box, - not_null window); + not_null<::Window::SessionController*> window); } // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 0ba4672931..d4d0093350 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -811,7 +811,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) { } if (data.is_need_rating() && _id && _accessHash) { const auto window = Core::App().windowFor( - Window::SeparateId(_user)); + ::Window::SeparateId(_user)); const auto session = &_user->session(); const auto callId = _id; const auto callAccessHash = _accessHash; @@ -1589,7 +1589,7 @@ void Call::handleRequestError(const QString &error) { : error; if (!inform.isEmpty()) { if (const auto window = Core::App().windowFor( - Window::SeparateId(_user))) { + ::Window::SeparateId(_user))) { window->show(Ui::MakeInformBox(inform)); } else { Ui::show(Ui::MakeInformBox(inform)); @@ -1608,7 +1608,7 @@ void Call::handleControllerError(const QString &error) { : QString(); if (!inform.isEmpty()) { if (const auto window = Core::App().windowFor( - Window::SeparateId(_user))) { + ::Window::SeparateId(_user))) { window->show(Ui::MakeInformBox(inform)); } else { Ui::show(Ui::MakeInformBox(inform)); diff --git a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp index 5c00536ca3..f6c568b48c 100644 --- a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp +++ b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp @@ -153,7 +153,7 @@ std::vector ComputeEmojiFingerprint( return result; } -object_ptr CreateFingerprintAndSignalBars( +base::unique_qptr CreateFingerprintAndSignalBars( not_null parent, not_null call) { class EmojiTooltipShower final : public Ui::AbstractTooltipShower { @@ -179,8 +179,8 @@ object_ptr CreateFingerprintAndSignalBars( }; - auto result = object_ptr(parent); - const auto raw = result.data(); + auto result = base::make_unique_q(parent); + const auto raw = result.get(); // Emoji tooltip. const auto shower = raw->lifetime().make_state( diff --git a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h index 285f9ebaff..36a10d4929 100644 --- a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h +++ b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.h @@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "base/object_ptr.h" +#include "base/unique_qptr.h" namespace Ui { class RpWidget; @@ -22,7 +22,7 @@ class Call; [[nodiscard]] std::vector ComputeEmojiFingerprint( bytes::const_span fingerprint); -[[nodiscard]] object_ptr CreateFingerprintAndSignalBars( +[[nodiscard]] base::unique_qptr CreateFingerprintAndSignalBars( not_null parent, not_null call); diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 7e2ae032b0..10302759de 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -349,7 +349,11 @@ void Instance::playSoundOnce(const QString &key) { void Instance::destroyCall(not_null call) { if (_currentCall.get() == call) { - _currentCallPanel->closeBeforeDestroy(); + const auto groupCallWindow = _currentGroupCallPanel + ? _currentGroupCallPanel->window().get() + : nullptr; + const auto reused = (_currentCallPanel->window() == groupCallWindow); + _currentCallPanel->closeBeforeDestroy(reused); _currentCallPanel = nullptr; auto taken = base::take(_currentCall); diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 3f2c0b31ac..5a95153d36 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_userpic.h" #include "calls/calls_video_bubble.h" #include "calls/calls_video_incoming.h" +#include "calls/calls_window.h" #include "ui/platform/ui_platform_window_title.h" #include "ui/widgets/call_button.h" #include "ui/widgets/buttons.h" @@ -95,116 +96,49 @@ constexpr auto kHideControlsQuickTimeout = 2 * crl::time(1000); )"; } -class Show final : public Main::SessionShow { -public: - explicit Show(not_null panel); - ~Show(); - - void showOrHideBoxOrLayer( - std::variant< - v::null_t, - object_ptr, - std::unique_ptr> &&layer, - Ui::LayerOptions options, - anim::type animated) const override; - [[nodiscard]] not_null toastParent() const override; - [[nodiscard]] bool valid() const override; - operator bool() const override; - - [[nodiscard]] Main::Session &session() const override; - -private: - const base::weak_ptr _panel; - -}; - -Show::Show(not_null panel) -: _panel(base::make_weak(panel)) { -} - -Show::~Show() = default; - -void Show::showOrHideBoxOrLayer( - std::variant< - v::null_t, - object_ptr, - std::unique_ptr> &&layer, - Ui::LayerOptions options, - anim::type animated) const { - using UniqueLayer = std::unique_ptr; - using ObjectBox = object_ptr; - if (auto layerWidget = std::get_if(&layer)) { - if (const auto panel = _panel.get()) { - panel->showLayer(std::move(*layerWidget), options, animated); - } - } else if (auto box = std::get_if(&layer)) { - if (const auto panel = _panel.get()) { - panel->showBox(std::move(*box), options, animated); - } - } else if (const auto panel = _panel.get()) { - panel->hideLayer(animated); - } -} - -not_null Show::toastParent() const { - const auto panel = _panel.get(); - Assert(panel != nullptr); - return panel->widget(); -} - -bool Show::valid() const { - return !_panel.empty(); -} - -Show::operator bool() const { - return valid(); -} - -Main::Session &Show::session() const { - const auto panel = _panel.get(); - Assert(panel != nullptr); - return panel->user()->session(); -} - } // namespace Panel::Panel(not_null call) : _call(call) , _user(call->user()) -, _layerBg(std::make_unique(widget())) -#ifndef Q_OS_MAC -, _controls(Ui::Platform::SetupSeparateTitleControls( - window(), - st::callTitle, - [=](bool maximized) { toggleFullScreen(maximized); })) -#endif // !Q_OS_MAC +, _window(std::make_shared()) , _bodySt(&st::callBodyLayout) -, _answerHangupRedial(widget(), st::callAnswer, &st::callHangup) -, _decline(widget(), object_ptr(widget(), st::callHangup)) -, _cancel(widget(), object_ptr(widget(), st::callCancel)) +, _answerHangupRedial( + std::in_place, + widget(), + st::callAnswer, + &st::callHangup) +, _decline( + std::in_place, + widget(), + object_ptr(widget(), st::callHangup)) +, _cancel( + std::in_place, + widget(), + object_ptr(widget(), st::callCancel)) , _screencast( + std::in_place, widget(), object_ptr( widget(), st::callScreencastOn, &st::callScreencastOff)) -, _camera(widget(), st::callCameraMute, &st::callCameraUnmute) +, _camera(std::in_place, widget(), st::callCameraMute, &st::callCameraUnmute) , _mute( + std::in_place, widget(), object_ptr( widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute)) , _addPeople( + std::in_place, widget(), object_ptr(widget(), st::callAddPeople)) -, _name(widget(), st::callName) -, _status(widget(), st::callStatus) +, _name(std::in_place, widget(), st::callName) +, _status(std::in_place, widget(), st::callStatus) , _hideControlsTimer([=] { requestControlsHidden(true); }) , _controlsShownForceTimer([=] { controlsShownForce(false); }) { - _layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox); - _layerBg->setHideByBackgroundClick(true); - _decline->setDuration(st::callPanelDuration); _decline->entity()->setText(tr::lng_call_decline()); _cancel->setDuration(st::callPanelDuration); @@ -234,67 +168,15 @@ bool Panel::isActive() const { } ConferencePanelMigration Panel::migrationInfo() const { - const auto handle = window()->windowHandle(); - return handle ? ConferencePanelMigration{ - .screen = handle->screen(), - .geometry = window()->geometry(), - } : ConferencePanelMigration(); + return ConferencePanelMigration{ .window = _window }; } -base::weak_ptr Panel::showToast( - const QString &text, - crl::time duration) { - return showToast({ - .text = { text }, - .duration = duration, - }); +std::shared_ptr Panel::sessionShow() { + return Main::MakeSessionShow(uiShow(), &_user->session()); } -base::weak_ptr Panel::showToast( - TextWithEntities &&text, - crl::time duration) { - return showToast({ - .text = std::move(text), - .duration = duration, - }); -} - -base::weak_ptr Panel::showToast( - Ui::Toast::Config &&config) { - if (!config.st) { - config.st = &st::callErrorToast; - } - return Show(this).showToast(std::move(config)); -} - -void Panel::showBox(object_ptr box) { - showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal); -} - -void Panel::showBox( - object_ptr box, - Ui::LayerOptions options, - anim::type animated) { - _layerBg->showBox(std::move(box), options, animated); -} - -void Panel::showLayer( - std::unique_ptr layer, - Ui::LayerOptions options, - anim::type animated) { - _layerBg->showLayer(std::move(layer), options, animated); -} - -void Panel::hideLayer(anim::type animated) { - _layerBg->hideAll(animated); -} - -bool Panel::isLayerShown() const { - return _layerBg->topShownLayer() != nullptr; -} - -std::shared_ptr Panel::uiShow() { - return std::make_shared(this); +std::shared_ptr Panel::uiShow() { + return _window->uiShow(); } void Panel::showAndActivate() { @@ -359,20 +241,16 @@ void Panel::initWindow() { } } return base::EventFilterResult::Continue; - }); + }, lifetime()); + const auto guard = base::make_weak(this); window()->setBodyTitleArea([=](QPoint widgetPoint) { using Flag = Ui::WindowTitleHitTestFlag; - if (!widget()->rect().contains(widgetPoint)) { + if (!guard + || !widget()->rect().contains(widgetPoint) + || _window->controlsHasHitTest(widgetPoint)) { return Flag::None | Flag(0); } -#ifndef Q_OS_MAC - using Result = Ui::Platform::HitTestResult; - const auto windowPoint = widget()->mapTo(window(), widgetPoint); - if (_controls->controls.hitTest(windowPoint) != Result::None) { - return Flag::None | Flag(0); - } -#endif // !Q_OS_MAC const auto buttonWidth = st::callCancel.button.width; const auto buttonsWidth = buttonWidth * 4; const auto inControls = (_fingerprint @@ -387,12 +265,15 @@ void Panel::initWindow() { if (inControls) { return Flag::None | Flag(0); } - const auto shown = _layerBg->topShownLayer(); + const auto shown = _window->topShownLayer(); return (!shown || !shown->geometry().contains(widgetPoint)) ? (Flag::Move | Flag::Menu | Flag::FullScreen) : Flag::None; }); + _window->maximizeRequests() | rpl::start_with_next([=](bool maximized) { + toggleFullScreen(maximized); + }, lifetime()); // Don't do that, it looks awful :( //#ifdef Q_OS_WIN // // On Windows we replace snap-to-top maximizing with fullscreen. @@ -426,12 +307,12 @@ void Panel::initWidget() { widget()->paintRequest( ) | rpl::start_with_next([=](QRect clip) { paint(clip); - }, widget()->lifetime()); + }, lifetime()); widget()->sizeValue( ) | rpl::skip(1) | rpl::start_with_next([=] { updateControlsGeometry(); - }, widget()->lifetime()); + }, lifetime()); } void Panel::initControls() { @@ -447,7 +328,7 @@ void Panel::initControls() { return; } else if (!env->desktopCaptureAllowed()) { if (auto box = Group::ScreenSharingPrivacyRequestBox()) { - showBox(std::move(box)); + uiShow()->showBox(std::move(box)); } } else if (const auto source = env->uniqueDesktopCaptureSource()) { if (!chooseSourceActiveDeviceId().isEmpty()) { @@ -467,7 +348,7 @@ void Panel::initControls() { }); _addPeople->entity()->setClickedCallback([=] { if (!_call || _call->state() != Call::State::Established) { - showToast(tr::lng_call_error_add_not_started(tr::now)); + uiShow()->showToast(tr::lng_call_error_add_not_started(tr::now)); return; } const auto call = _call; @@ -484,7 +365,7 @@ void Panel::initControls() { *creating = true; const auto sharingLink = users.empty(); Group::MakeConferenceCall({ - .show = uiShow(), + .show = sessionShow(), .finished = finish, .joining = true, .info = { @@ -506,7 +387,7 @@ void Panel::initControls() { const auto share = crl::guard(call, [=] { create({}); }); - showBox(Group::PrepareInviteBox(call, invite, share)); + uiShow()->showBox(Group::PrepareInviteBox(call, invite, share)); }); _updateDurationTimer.setCallback([this] { @@ -559,9 +440,9 @@ void Panel::initConferenceInvite() { if (count < 2) { return; } - _conferenceParticipants.create(widget()); + _conferenceParticipants = base::make_unique_q(widget()); _conferenceParticipants->show(); - const auto raw = _conferenceParticipants.data(); + const auto raw = _conferenceParticipants.get(); auto peers = std::vector>(); for (const auto &peer : participants) { @@ -689,10 +570,9 @@ void Panel::reinitWithCall(Call *call) { updateControlsShown(); }); if (!_call) { - _fingerprint.destroy(); + _fingerprint = nullptr; _incoming = nullptr; _outgoingVideoBubble = nullptr; - _powerSaveBlocker = nullptr; return; } @@ -716,7 +596,7 @@ void Panel::reinitWithCall(Call *call) { if (muted) { createRemoteAudioMute(); } else { - _remoteAudioMute.destroy(); + _remoteAudioMute = nullptr; showRemoteLowBattery(); } }, _callLifetime); @@ -725,7 +605,7 @@ void Panel::reinitWithCall(Call *call) { if (state == Call::RemoteBatteryState::Low) { createRemoteLowBattery(); } else { - _remoteLowBattery.destroy(); + _remoteLowBattery = nullptr; } }, _callLifetime); _userpic = std::make_unique( @@ -738,7 +618,7 @@ void Panel::reinitWithCall(Call *call) { _incoming = std::make_unique( widget(), _call->videoIncoming(), - _window.backend()); + _window->backend()); _incoming->widget()->hide(); _incoming->rp()->shownValue() | rpl::start_with_next([=] { @@ -886,7 +766,7 @@ void Panel::reinitWithCall(Call *call) { } Unexpected("Error type in _call->errors()."); }(); - showToast(text); + uiShow()->showToast(text); }, _callLifetime); _name->setText(_user->name()); @@ -902,16 +782,11 @@ void Panel::reinitWithCall(Call *call) { _mute->raise(); _addPeople->raise(); - _powerSaveBlocker = std::make_unique( - base::PowerSaveBlockType::PreventDisplaySleep, - u"Video call is active"_q, - window()->windowHandle()); - _incoming->widget()->lower(); } void Panel::createRemoteAudioMute() { - _remoteAudioMute.create( + _remoteAudioMute = base::make_unique_q>( widget(), object_ptr( widget(), @@ -948,7 +823,7 @@ void Panel::createRemoteAudioMute() { } void Panel::createRemoteLowBattery() { - _remoteLowBattery.create( + _remoteLowBattery = base::make_unique_q>( widget(), object_ptr( widget(), @@ -964,7 +839,7 @@ void Panel::createRemoteLowBattery() { style::PaletteChanged( ) | rpl::start_with_next([=] { - _remoteLowBattery.destroy(); + _remoteLowBattery = nullptr; createRemoteLowBattery(); }, _remoteLowBattery->lifetime()); @@ -1032,11 +907,9 @@ void Panel::initLayout() { }) | rpl::start_with_next([=](const Data::PeerUpdate &update) { _name->setText(_call->user()->name()); updateControlsGeometry(); - }, widget()->lifetime()); + }, lifetime()); -#ifndef Q_OS_MAC - _controls->wrap.raise(); -#endif // !Q_OS_MAC + _window->raiseControls(); } void Panel::showControls() { @@ -1058,13 +931,16 @@ void Panel::showControls() { showRemoteLowBattery(); } -void Panel::closeBeforeDestroy() { - window()->close(); +void Panel::closeBeforeDestroy(bool windowIsReused) { + if (!windowIsReused) { + window()->close(); + } reinitWithCall(nullptr); + _lifetime.destroy(); } rpl::lifetime &Panel::lifetime() { - return window()->lifetime(); + return _lifetime; } void Panel::initGeometry() { @@ -1202,7 +1078,7 @@ void Panel::updateControlsGeometry() { _controlsShown ? 1. : 0.); if (_fingerprint) { #ifndef Q_OS_MAC - const auto controlsGeometry = _controls->controls.geometry(); + const auto controlsGeometry = _window->controlsGeometry(); const auto halfWidth = widget()->width() / 2; const auto minLeft = (controlsGeometry.center().x() < halfWidth) ? (controlsGeometry.width() + st::callFingerprintTop) @@ -1391,11 +1267,11 @@ bool Panel::handleClose() const { } not_null Panel::window() const { - return _window.window(); + return _window->window(); } not_null Panel::widget() const { - return _window.widget(); + return _window->widget(); } not_null Panel::user() const { @@ -1407,17 +1283,16 @@ void Panel::stateChanged(State state) { updateStatusText(state); + const auto isBusy = (state == State::Busy); + const auto isWaitingUser = (state == State::WaitingUserConfirmation); + _window->togglePowerSaveBlocker(!isBusy && !isWaitingUser); + if ((state != State::HangingUp) && (state != State::MigrationHangingUp) && (state != State::Ended) && (state != State::EndedByOtherDevice) && (state != State::FailedHangingUp) && (state != State::Failed)) { - const auto isBusy = (state == State::Busy); - const auto isWaitingUser = (state == State::WaitingUserConfirmation); - if (isBusy) { - _powerSaveBlocker = nullptr; - } if (_startVideo && !isWaitingUser) { _startVideo = nullptr; } else if (!_startVideo && isWaitingUser) { @@ -1472,7 +1347,7 @@ void Panel::stateChanged(State state) { refreshAnswerHangupRedialLabel(); } if (!_call->isKeyShaForFingerprintReady()) { - _fingerprint.destroy(); + _fingerprint = nullptr; } else if (!_fingerprint) { _fingerprint = CreateFingerprintAndSignalBars(widget(), _call); updateControlsGeometry(); diff --git a/Telegram/SourceFiles/calls/calls_panel.h b/Telegram/SourceFiles/calls/calls_panel.h index 13ba30c258..bcdf373c42 100644 --- a/Telegram/SourceFiles/calls/calls_panel.h +++ b/Telegram/SourceFiles/calls/calls_panel.h @@ -7,14 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "base/weak_ptr.h" -#include "base/timer.h" -#include "base/object_ptr.h" -#include "base/unique_qptr.h" #include "calls/calls_call.h" #include "calls/group/ui/desktop_capture_choose_source.h" #include "ui/effects/animations.h" -#include "ui/gl/gl_window.h" #include "ui/rp_widget.h" class Image; @@ -32,6 +27,7 @@ class SessionShow; } // namespace Main namespace Ui { +class Show; class BoxContent; class LayerWidget; enum class LayerOption; @@ -64,6 +60,7 @@ struct CallBodyLayout; namespace Calls { +class Window; class Userpic; class SignalBars; class VideoBubble; @@ -84,32 +81,11 @@ public: [[nodiscard]] ConferencePanelMigration migrationInfo() const; - base::weak_ptr showToast( - const QString &text, - crl::time duration = 0); - base::weak_ptr showToast( - TextWithEntities &&text, - crl::time duration = 0); - base::weak_ptr showToast( - Ui::Toast::Config &&config); - - void showBox(object_ptr box); - void showBox( - object_ptr box, - Ui::LayerOptions options, - anim::type animated = anim::type::normal); - void showLayer( - std::unique_ptr layer, - Ui::LayerOptions options, - anim::type animated = anim::type::normal); - void hideLayer(anim::type animated = anim::type::normal); - [[nodiscard]] bool isLayerShown() const; - void showAndActivate(); void minimize(); void toggleFullScreen(); void replaceCall(not_null call); - void closeBeforeDestroy(); + void closeBeforeDestroy(bool windowIsReused = false); QWidget *chooseSourceParent() override; QString chooseSourceActiveDeviceId() override; @@ -123,7 +99,10 @@ public: [[nodiscard]] rpl::producer startOutgoingRequests() const; - [[nodiscard]] std::shared_ptr uiShow(); + [[nodiscard]] std::shared_ptr sessionShow(); + [[nodiscard]] std::shared_ptr uiShow(); + + [[nodiscard]] not_null window() const; [[nodiscard]] rpl::lifetime &lifetime(); @@ -138,8 +117,6 @@ private: StartCall, }; - [[nodiscard]] not_null window() const; - void paint(QRect clip); void initWindow(); @@ -184,43 +161,35 @@ private: Call *_call = nullptr; not_null _user; - Ui::GL::Window _window; - const std::unique_ptr _layerBg; + std::shared_ptr _window; std::unique_ptr _incoming; -#ifndef Q_OS_MAC - std::unique_ptr _controls; -#endif // !Q_OS_MAC - - std::unique_ptr _powerSaveBlocker; - QSize _incomingFrameSize; rpl::lifetime _callLifetime; not_null _bodySt; - object_ptr _answerHangupRedial; - object_ptr> _decline; - object_ptr> _cancel; + base::unique_qptr _answerHangupRedial; + base::unique_qptr> _decline; + base::unique_qptr> _cancel; bool _hangupShown = false; bool _conferenceSupported = false; bool _outgoingPreviewInBody = false; std::optional _answerHangupRedialState; Ui::Animations::Simple _hangupShownProgress; - object_ptr> _screencast; - object_ptr _camera; + base::unique_qptr> _screencast; + base::unique_qptr _camera; Ui::CallButton *_cameraDeviceToggle = nullptr; base::unique_qptr _startVideo; - object_ptr> _mute; + base::unique_qptr> _mute; Ui::CallButton *_audioDeviceToggle = nullptr; - object_ptr < Ui::FadeWrap> _addPeople; - object_ptr _name; - object_ptr _status; - object_ptr _conferenceParticipants = { nullptr }; - object_ptr _fingerprint = { nullptr }; - object_ptr> _remoteAudioMute = { nullptr }; - object_ptr> _remoteLowBattery - = { nullptr }; + base::unique_qptr> _addPeople; + base::unique_qptr _name; + base::unique_qptr _status; + base::unique_qptr _conferenceParticipants; + base::unique_qptr _fingerprint; + base::unique_qptr> _remoteAudioMute; + base::unique_qptr> _remoteLowBattery; std::unique_ptr _userpic; std::unique_ptr _outgoingVideoBubble; QPixmap _bottomShadow; @@ -245,6 +214,8 @@ private: rpl::event_stream _startOutgoingRequests; + rpl::lifetime _lifetime; + }; } // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_window.cpp b/Telegram/SourceFiles/calls/calls_window.cpp new file mode 100644 index 0000000000..16b754d660 --- /dev/null +++ b/Telegram/SourceFiles/calls/calls_window.cpp @@ -0,0 +1,250 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "calls/calls_window.h" + +#include "base/power_save_blocker.h" +#include "ui/platform/ui_platform_window_title.h" +#include "ui/widgets/rp_window.h" +#include "ui/layers/layer_manager.h" +#include "ui/layers/show.h" +#include "styles/style_calls.h" + +namespace Calls { +namespace { + +class Show final : public Ui::Show { +public: + explicit Show(not_null window); + ~Show(); + + void showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + Ui::LayerOptions options, + anim::type animated) const override; + [[nodiscard]] not_null toastParent() const override; + [[nodiscard]] bool valid() const override; + operator bool() const override; + +private: + const base::weak_ptr _window; + +}; + +Show::Show(not_null window) +: _window(base::make_weak(window)) { +} + +Show::~Show() = default; + +void Show::showOrHideBoxOrLayer( + std::variant< + v::null_t, + object_ptr, + std::unique_ptr> &&layer, + Ui::LayerOptions options, + anim::type animated) const { + using UniqueLayer = std::unique_ptr; + using ObjectBox = object_ptr; + if (auto layerWidget = std::get_if(&layer)) { + if (const auto window = _window.get()) { + window->showLayer(std::move(*layerWidget), options, animated); + } + } else if (auto box = std::get_if(&layer)) { + if (const auto window = _window.get()) { + window->showBox(std::move(*box), options, animated); + } + } else if (const auto window = _window.get()) { + window->hideLayer(animated); + } +} + +not_null Show::toastParent() const { + const auto window = _window.get(); + Assert(window != nullptr); + return window->widget(); +} + +bool Show::valid() const { + return !_window.empty(); +} + +Show::operator bool() const { + return valid(); +} + +} // namespace + +Window::Window() +: _layerBg(std::make_unique(widget())) +#ifndef Q_OS_MAC +, _controls(Ui::Platform::SetupSeparateTitleControls( + window(), + st::callTitle, + [=](bool maximized) { _maximizeRequests.fire_copy(maximized); }, + _controlsTop.value())) +#endif // !Q_OS_MAC +{ + _layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox); + _layerBg->setHideByBackgroundClick(true); +} + +Window::~Window() = default; + +Ui::GL::Backend Window::backend() const { + return _window.backend(); +} + +not_null Window::window() const { + return _window.window(); +} + +not_null Window::widget() const { + return _window.widget(); +} + +void Window::raiseControls() { +#ifndef Q_OS_MAC + _controls->wrap.raise(); +#endif // !Q_OS_MAC +} + +void Window::setControlsStyle(const style::WindowTitle &st) { +#ifndef Q_OS_MAC + _controls->controls.setStyle(st); +#endif // Q_OS_MAC +} + +void Window::setControlsShown(float64 shown) { +#ifndef Q_OS_MAC + _controlsTop = anim::interpolate(-_controls->wrap.height(), 0, shown); +#endif // Q_OS_MAC +} + +int Window::controlsWrapTop() const { +#ifndef Q_OS_MAC + return _controls->wrap.y(); +#else // Q_OS_MAC + return 0; +#endif // Q_OS_MAC +} + +QRect Window::controlsGeometry() const { +#ifndef Q_OS_MAC + return _controls->controls.geometry(); +#else // Q_OS_MAC + return QRect(); +#endif // Q_OS_MAC +} + +auto Window::controlsLayoutChanges() const +-> rpl::producer { +#ifndef Q_OS_MAC + return _controls->controls.layout().changes(); +#else // Q_OS_MAC + return rpl::never(); +#endif // Q_OS_MAC +} + +bool Window::controlsHasHitTest(QPoint widgetPoint) const { +#ifndef Q_OS_MAC + using Result = Ui::Platform::HitTestResult; + const auto windowPoint = widget()->mapTo(window(), widgetPoint); + return (_controls->controls.hitTest(windowPoint) != Result::None); +#else // Q_OS_MAC + return false; +#endif // Q_OS_MAC +} + +rpl::producer Window::maximizeRequests() const { + return _maximizeRequests.events(); +} + +base::weak_ptr Window::showToast( + const QString &text, + crl::time duration) { + return Show(this).showToast(text, duration); +} + +base::weak_ptr Window::showToast( + TextWithEntities &&text, + crl::time duration) { + return Show(this).showToast(std::move(text), duration); +} + +base::weak_ptr Window::showToast( + Ui::Toast::Config &&config) { + return Show(this).showToast(std::move(config)); +} + +void Window::raiseLayers() { + _layerBg->raise(); +} + +const Ui::LayerWidget *Window::topShownLayer() const { + return _layerBg->topShownLayer(); +} + +void Window::showBox(object_ptr box) { + showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal); +} + +void Window::showBox( + object_ptr box, + Ui::LayerOptions options, + anim::type animated) { + _showingLayer.fire({}); + if (window()->width() < st::groupCallWidth + || window()->height() < st::groupCallWidth) { + window()->resize( + std::max(window()->width(), st::groupCallWidth), + std::max(window()->height(), st::groupCallWidth)); + } + _layerBg->showBox(std::move(box), options, animated); +} + +void Window::showLayer( + std::unique_ptr layer, + Ui::LayerOptions options, + anim::type animated) { + _showingLayer.fire({}); + if (window()->width() < st::groupCallWidth + || window()->height() < st::groupCallWidth) { + window()->resize( + std::max(window()->width(), st::groupCallWidth), + std::max(window()->height(), st::groupCallWidth)); + } + _layerBg->showLayer(std::move(layer), options, animated); +} + +void Window::hideLayer(anim::type animated) { + _layerBg->hideAll(animated); +} + +bool Window::isLayerShown() const { + return _layerBg->topShownLayer() != nullptr; +} + +std::shared_ptr Window::uiShow() { + return std::make_shared(this); +} + +void Window::togglePowerSaveBlocker(bool enabled) { + if (!enabled) { + _powerSaveBlocker = nullptr; + } else if (!_powerSaveBlocker) { + _powerSaveBlocker = std::make_unique( + base::PowerSaveBlockType::PreventDisplaySleep, + u"Video call is active"_q, + window()->windowHandle()); + } +} + +} // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_window.h b/Telegram/SourceFiles/calls/calls_window.h new file mode 100644 index 0000000000..5963b4fc4d --- /dev/null +++ b/Telegram/SourceFiles/calls/calls_window.h @@ -0,0 +1,112 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "base/object_ptr.h" +#include "ui/effects/animations.h" +#include "ui/gl/gl_window.h" + +namespace base { +class PowerSaveBlocker; +} // namespace base + +namespace style { +struct WindowTitle; +} // namespace style + +namespace Ui { +class BoxContent; +class RpWindow; +class RpWidget; +class LayerManager; +class LayerWidget; +enum class LayerOption; +using LayerOptions = base::flags; +class Show; +} // namespace Ui + +namespace Ui::Platform { +struct SeparateTitleControls; +struct TitleLayout; +} // namespace Ui::Platform + +namespace Ui::Toast { +struct Config; +class Instance; +} // namespace Ui::Toast + +namespace Calls { + +class Window final : public base::has_weak_ptr { +public: + Window(); + ~Window(); + + [[nodiscard]] Ui::GL::Backend backend() const; + [[nodiscard]] not_null window() const; + [[nodiscard]] not_null widget() const; + + void raiseControls(); + void setControlsStyle(const style::WindowTitle &st); + void setControlsShown(float64 shown); + [[nodiscard]] int controlsWrapTop() const; + [[nodiscard]] QRect controlsGeometry() const; + [[nodiscard]] auto controlsLayoutChanges() const + -> rpl::producer; + [[nodiscard]] bool controlsHasHitTest(QPoint widgetPoint) const; + [[nodiscard]] rpl::producer maximizeRequests() const; + + void raiseLayers(); + [[nodiscard]] const Ui::LayerWidget *topShownLayer() const; + + base::weak_ptr showToast( + const QString &text, + crl::time duration = 0); + base::weak_ptr showToast( + TextWithEntities &&text, + crl::time duration = 0); + base::weak_ptr showToast( + Ui::Toast::Config &&config); + + void showBox(object_ptr box); + void showBox( + object_ptr box, + Ui::LayerOptions options, + anim::type animated = anim::type::normal); + void showLayer( + std::unique_ptr layer, + Ui::LayerOptions options, + anim::type animated = anim::type::normal); + void hideLayer(anim::type animated = anim::type::normal); + [[nodiscard]] bool isLayerShown() const; + + [[nodiscard]] rpl::producer<> showingLayer() const { + return _showingLayer.events(); + } + + [[nodiscard]] std::shared_ptr uiShow(); + + void togglePowerSaveBlocker(bool enabled); + +private: + Ui::GL::Window _window; + const std::unique_ptr _layerBg; + +#ifndef Q_OS_MAC + rpl::variable _controlsTop = 0; + const std::unique_ptr _controls; +#endif // !Q_OS_MAC + + std::unique_ptr _powerSaveBlocker; + + rpl::event_stream _maximizeRequests; + rpl::event_stream<> _showingLayer; + +}; + +} // namespace Calls diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.h b/Telegram/SourceFiles/calls/group/calls_group_common.h index ce06d3223c..57b160c8c3 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.h +++ b/Telegram/SourceFiles/calls/group/calls_group_common.h @@ -48,6 +48,8 @@ class SessionController; namespace Calls { +class Window; + struct InviteRequest { not_null user; bool video = false; @@ -75,8 +77,7 @@ struct StartConferenceInfo { }; struct ConferencePanelMigration { - QScreen *screen = nullptr; - QRect geometry; + std::shared_ptr window; }; } // namespace Calls diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index 5b4e87b622..f9a1727729 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -1359,22 +1359,22 @@ base::unique_qptr Members::Controller::createRowContextMenu( window->invokeForSessionController( account, participantPeer, - [&](not_null newController) { + [&](not_null<::Window::SessionController*> newController) { callback(newController); newController->widget()->activate(); }); } }; const auto showProfile = [=] { - withActiveWindow([=](not_null window) { + withActiveWindow([=](not_null<::Window::SessionController*> window) { window->showPeerInfo(participantPeer); }); }; const auto showHistory = [=] { - withActiveWindow([=](not_null window) { + withActiveWindow([=](not_null<::Window::SessionController*> window) { window->showPeerHistory( participantPeer, - Window::SectionShow::Way::Forward); + ::Window::SectionShow::Way::Forward); }); }; const auto removeFromVoiceChat = crl::guard(this, [=] { diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 27771e27db..d22dc923f5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -17,7 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/ui/calls_group_scheduled_labels.h" #include "calls/group/ui/desktop_capture_choose_source.h" #include "calls/calls_emoji_fingerprint.h" -#include "ui/platform/ui_platform_window_title.h" +#include "calls/calls_window.h" +#include "ui/platform/ui_platform_window_title.h" // TitleLayout #include "ui/platform/ui_platform_utility.h" #include "ui/controls/call_mute_button.h" #include "ui/widgets/buttons.h" @@ -29,7 +30,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/rp_window.h" #include "ui/chat/group_call_bar.h" #include "ui/controls/userpic_button.h" -#include "ui/layers/layer_manager.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" @@ -54,7 +54,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "base/qt_signal_producer.h" #include "base/timer_rpl.h" -#include "base/power_save_blocker.h" #include "apiwrap.h" // api().kick. #include "api/api_chat_participants.h" // api().kick. #include "webrtc/webrtc_environment.h" @@ -91,77 +90,6 @@ constexpr auto kHideControlsTimeout = 5 * crl::time(1000); return result; } -class Show final : public Main::SessionShow { -public: - explicit Show(not_null panel); - ~Show(); - - void showOrHideBoxOrLayer( - std::variant< - v::null_t, - object_ptr, - std::unique_ptr> &&layer, - Ui::LayerOptions options, - anim::type animated) const override; - [[nodiscard]] not_null toastParent() const override; - [[nodiscard]] bool valid() const override; - operator bool() const override; - - [[nodiscard]] Main::Session &session() const override; - -private: - const base::weak_ptr _panel; - -}; - -Show::Show(not_null panel) -: _panel(base::make_weak(panel)) { -} - -Show::~Show() = default; - -void Show::showOrHideBoxOrLayer( - std::variant< - v::null_t, - object_ptr, - std::unique_ptr> &&layer, - Ui::LayerOptions options, - anim::type animated) const { - using UniqueLayer = std::unique_ptr; - using ObjectBox = object_ptr; - if (auto layerWidget = std::get_if(&layer)) { - if (const auto panel = _panel.get()) { - panel->showLayer(std::move(*layerWidget), options, animated); - } - } else if (auto box = std::get_if(&layer)) { - if (const auto panel = _panel.get()) { - panel->showBox(std::move(*box), options, animated); - } - } else if (const auto panel = _panel.get()) { - panel->hideLayer(animated); - } -} - -not_null Show::toastParent() const { - const auto panel = _panel.get(); - Assert(panel != nullptr); - return panel->widget(); -} - -bool Show::valid() const { - return !_panel.empty(); -} - -Show::operator bool() const { - return valid(); -} - -Main::Session &Show::session() const { - const auto panel = _panel.get(); - Assert(panel != nullptr); - return panel->call()->peer()->session(); -} - #ifdef Q_OS_WIN void UnpinMaximized(not_null widget) { SetWindowPos( @@ -198,20 +126,12 @@ Panel::Panel(not_null call) Panel::Panel(not_null call, ConferencePanelMigration info) : _call(call) , _peer(call->peer()) -, _layerBg(std::make_unique(widget())) -#ifndef Q_OS_MAC -, _controls(Ui::Platform::SetupSeparateTitleControls( - window(), - st::groupCallTitle, - nullptr, - _controlsTop.value())) -#endif // !Q_OS_MAC -, _powerSaveBlocker(std::make_unique( - base::PowerSaveBlockType::PreventDisplaySleep, - u"Video chat is active"_q, - window()->windowHandle())) +, _window(info.window ? info.window : std::make_shared()) , _viewport( - std::make_unique(widget(), PanelMode::Wide, _window.backend())) + std::make_unique( + widget(), + PanelMode::Wide, + _window->backend())) , _mute(std::make_unique( widget(), st::callMuteButton, @@ -241,9 +161,6 @@ Panel::Panel(not_null call, ConferencePanelMigration info) return result; }) , _hideControlsTimer([=] { toggleWideControls(false); }) { - _layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox); - _layerBg->setHideByBackgroundClick(true); - _viewport->widget()->hide(); if (!_viewport->requireARGB32()) { _call->setNotRequireARGB32(); @@ -287,25 +204,12 @@ bool Panel::isActive() const { return window()->isActiveWindow() && isVisible(); } -base::weak_ptr Panel::showToast( - const QString &text, - crl::time duration) { - return Show(this).showToast(text, duration); +std::shared_ptr Panel::sessionShow() { + return Main::MakeSessionShow(uiShow(), &_peer->session()); } -base::weak_ptr Panel::showToast( - TextWithEntities &&text, - crl::time duration) { - return Show(this).showToast(std::move(text), duration); -} - -base::weak_ptr Panel::showToast( - Ui::Toast::Config &&config) { - return Show(this).showToast(std::move(config)); -} - -std::shared_ptr Panel::uiShow() { - return std::make_shared(this); +std::shared_ptr Panel::uiShow() { + return _window->uiShow(); } void Panel::minimize() { @@ -394,12 +298,20 @@ void Panel::initWindow() { subscribeToPeerChanges(); } + const auto updateFullScreen = [=] { + const auto state = window()->windowState(); + const auto full = (state & Qt::WindowFullScreen) + || (state & Qt::WindowMaximized); + _rtmpFull = _call->rtmp() && full; + _fullScreenOrMaximized = full; + }; base::install_event_filter(window().get(), [=](not_null e) { - if (e->type() == QEvent::Close && handleClose()) { + const auto type = e->type(); + if (type == QEvent::Close && handleClose()) { e->ignore(); return base::EventFilterResult::Cancel; - } else if (e->type() == QEvent::KeyPress - || e->type() == QEvent::KeyRelease) { + } else if (_call->rtmp() + && (type == QEvent::KeyPress || type == QEvent::KeyRelease)) { const auto key = static_cast(e.get())->key(); if (key == Qt::Key_Space) { _call->pushToTalk( @@ -409,16 +321,19 @@ void Panel::initWindow() { && _fullScreenOrMaximized.current()) { toggleFullScreen(); } - } else if (e->type() == QEvent::WindowStateChange && _call->rtmp()) { - const auto state = window()->windowState(); - _fullScreenOrMaximized = (state & Qt::WindowFullScreen) - || (state & Qt::WindowMaximized); + } else if (type == QEvent::WindowStateChange) { + updateFullScreen(); } return base::EventFilterResult::Continue; - }); + }, lifetime()); + updateFullScreen(); + const auto guard = base::make_weak(this); window()->setBodyTitleArea([=](QPoint widgetPoint) { using Flag = Ui::WindowTitleHitTestFlag; + if (!guard) { + return (Flag::None | Flag(0)); + } const auto titleRect = QRect( 0, 0, @@ -434,7 +349,7 @@ void Panel::initWindow() { if (!moveable) { return (Flag::None | Flag(0)); } - const auto shown = _layerBg->topShownLayer(); + const auto shown = _window->topShownLayer(); return (!shown || !shown->geometry().contains(widgetPoint)) ? (Flag::Move | Flag::Menu | Flag::Maximize) : Flag::None; @@ -444,6 +359,23 @@ void Panel::initWindow() { ) | rpl::start_with_next([=] { updateMode(); }, lifetime()); + + _window->maximizeRequests() | rpl::start_with_next([=](bool maximized) { + if (_call->rtmp()) { + toggleFullScreen(maximized); + } else { + window()->setWindowState(maximized + ? Qt::WindowMaximized + : Qt::WindowNoState); + } + }, lifetime()); + + _window->showingLayer() | rpl::start_with_next([=] { + hideStickedTooltip(StickedTooltipHide::Unavailable); + }, lifetime()); + + _window->setControlsStyle(st::groupCallTitle); + _window->togglePowerSaveBlocker(true); } void Panel::initWidget() { @@ -462,7 +394,7 @@ void Panel::initWidget() { // some geometries depends on _controls->controls.geometry, // which is not updated here yet. - crl::on_main(widget(), [=] { updateControlsGeometry(); }); + crl::on_main(this, [=] { updateControlsGeometry(); }); }, lifetime()); } @@ -471,7 +403,7 @@ void Panel::endCall() { _call->hangup(); return; } - showBox(Box( + uiShow()->showBox(Box( LeaveBox, _call, false, @@ -501,7 +433,7 @@ void Panel::startScheduledNow() { .confirmText = tr::lng_group_call_start_now(), }); *box = owned.data(); - showBox(std::move(owned)); + uiShow()->showBox(std::move(owned)); } } @@ -608,10 +540,15 @@ void Panel::initControls() { } void Panel::toggleFullScreen() { - if (_fullScreenOrMaximized.current() || window()->isFullScreen()) { - window()->showNormal(); - } else { + toggleFullScreen( + !_fullScreenOrMaximized.current() && !window()->isFullScreen()); +} + +void Panel::toggleFullScreen(bool fullscreen) { + if (fullscreen) { window()->showFullScreen(); + } else { + window()->showNormal(); } } @@ -630,7 +567,7 @@ void Panel::refreshLeftButton() { _callShare.destroy(); _settings.create(widget(), st::groupCallSettings); _settings->setClickedCallback([=] { - showBox(Box(SettingsBox, _call)); + uiShow()->showBox(Box(SettingsBox, _call)); }); trackControls(_trackControls, true); } @@ -915,13 +852,13 @@ void Panel::setupMembers() { _countdown.destroy(); _startsWhen.destroy(); - _members.create(widget(), _call, mode(), _window.backend()); + _members.create(widget(), _call, mode(), _window->backend()); setupVideo(_viewport.get()); setupVideo(_members->viewport()); _viewport->mouseInsideValue( ) | rpl::filter([=] { - return !_fullScreenOrMaximized.current(); + return !_rtmpFull; }) | rpl::start_with_next([=](bool inside) { toggleWideControls(inside); }, _viewport->lifetime()); @@ -996,7 +933,7 @@ Fn finished)> Panel::shareConferenceLinkCallback() { onstack(!link.isEmpty()); } }; - ExportConferenceCallLink(uiShow(), _call->conferenceCall(), { + ExportConferenceCallLink(sessionShow(), _call->conferenceCall(), { .finished = done, .st = DarkConferenceCallLinkStyle(), }); @@ -1004,8 +941,9 @@ Fn finished)> Panel::shareConferenceLinkCallback() { } void Panel::migrationShowShareLink() { + uiShow()->hideLayer(anim::type::instant); ShowConferenceCallLinkBox( - uiShow(), + sessionShow(), _call->conferenceCall(), _call->existingConferenceLink(), { .st = DarkConferenceCallLinkStyle() }); @@ -1013,7 +951,7 @@ void Panel::migrationShowShareLink() { void Panel::migrationInviteUsers(std::vector users) { const auto done = [=](InviteResult result) { - showToast({ ComposeInviteResultToast(result) }); + uiShow()->showToast({ ComposeInviteResultToast(result) }); }; _call->inviteUsers(std::move(users), crl::guard(this, done)); } @@ -1100,7 +1038,7 @@ void Panel::raiseControls() { if (_pinOnTop) { _pinOnTop->raise(); } - _layerBg->raise(); + _window->raiseLayers(); if (_niceTooltip) { _niceTooltip->raise(); } @@ -1178,7 +1116,7 @@ void Panel::toggleWideControls(bool shown) { return; } _showWideControls = shown; - crl::on_main(widget(), [=] { + crl::on_main(this, [=] { updateWideControlsVisibility(); }); } @@ -1189,7 +1127,7 @@ void Panel::updateWideControlsVisibility() { if (_wideControlsShown == shown) { return; } - _viewport->setCursorShown(!_fullScreenOrMaximized.current() || shown); + _viewport->setCursorShown(!_rtmpFull || shown); _wideControlsShown = shown; _wideControlsAnimation.start( [=] { updateButtonsGeometry(); }, @@ -1216,7 +1154,7 @@ void Panel::subscribeToChanges(not_null real) { const auto skip = st::groupCallRecordingMarkSkip; _recordingMark->resize(size + 2 * skip, size + 2 * skip); _recordingMark->setClickedCallback([=] { - showToast({ (livestream + uiShow()->showToast({ (livestream ? tr::lng_group_call_is_recorded_channel : real->recordVideo() ? tr::lng_group_call_is_recorded_video @@ -1262,7 +1200,7 @@ void Panel::subscribeToChanges(not_null real) { *startedAsVideo = isVideo; } validateRecordingMark(recorded); - showToast((recorded + uiShow()->showToast((recorded ? (livestream ? tr::lng_group_call_recording_started_channel : isVideo @@ -1323,7 +1261,7 @@ void Panel::createPinOnTop() { pin ? &st::groupCallPinnedOnTop : nullptr, pin ? &st::groupCallPinnedOnTop : nullptr); if (!_pinOnTop->isHidden()) { - showToast({ pin + uiShow()->showToast({ pin ? tr::lng_group_call_pinned_on_top(tr::now) : tr::lng_group_call_unpinned_on_top(tr::now) }); } @@ -1331,11 +1269,9 @@ void Panel::createPinOnTop() { }; _fullScreenOrMaximized.value( ) | rpl::start_with_next([=](bool fullScreenOrMaximized) { -#ifndef Q_OS_MAC - _controls->controls.setStyle(fullScreenOrMaximized + _window->setControlsStyle(fullScreenOrMaximized ? st::callTitle : st::groupCallTitle); -#endif // Q_OS_MAC _pinOnTop->setVisible(!fullScreenOrMaximized); if (fullScreenOrMaximized) { @@ -1425,7 +1361,7 @@ void Panel::refreshTopButton() { void Panel::screenSharingPrivacyRequest() { if (auto box = ScreenSharingPrivacyRequestBox()) { - showBox(std::move(box)); + uiShow()->showBox(std::move(box)); } } @@ -1476,7 +1412,7 @@ void Panel::chooseShareScreenSource() { .confirmText = tr::lng_continue(), }); *shared = box.data(); - showBox(std::move(box)); + uiShow()->showBox(std::move(box)); } void Panel::chooseJoinAs() { @@ -1487,7 +1423,7 @@ void Panel::chooseJoinAs() { _joinAsProcess.start( _peer, context, - std::make_shared(this), + uiShow(), callback, _call->joinAs()); } @@ -1508,7 +1444,7 @@ void Panel::showMainMenu() { wide, [=] { chooseJoinAs(); }, [=] { chooseShareScreenSource(); }, - [=](auto box) { showBox(std::move(box)); }); + [=](auto box) { uiShow()->showBox(std::move(box)); }); if (_menu->empty()) { _wideMenuShown = false; _menu.destroy(); @@ -1574,21 +1510,21 @@ void Panel::addMembers() { const auto conferenceLimit = appConfig.confcallSizeLimit(); if (_call->conference() && _call->conferenceCall()->fullCount() >= conferenceLimit) { - showToast({ tr::lng_group_call_invite_limit(tr::now) }); + uiShow()->showToast({ tr::lng_group_call_invite_limit(tr::now) }); } const auto showToastCallback = [=](TextWithEntities &&text) { - showToast(std::move(text)); + uiShow()->showToast(std::move(text)); }; const auto link = _call->conference() ? shareConferenceLinkCallback() : nullptr; if (auto box = PrepareInviteBox(_call, showToastCallback, link)) { - showBox(std::move(box)); + uiShow()->showBox(std::move(box)); } } void Panel::kickParticipant(not_null participantPeer) { - showBox(Box([=](not_null box) { + uiShow()->showBox(Box([=](not_null box) { box->addRow( object_ptr( box.get(), @@ -1621,46 +1557,6 @@ void Panel::kickParticipant(not_null participantPeer) { })); } -void Panel::showBox(object_ptr box) { - showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal); -} - -void Panel::showBox( - object_ptr box, - Ui::LayerOptions options, - anim::type animated) { - hideStickedTooltip(StickedTooltipHide::Unavailable); - if (window()->width() < st::groupCallWidth - || window()->height() < st::groupCallWidth) { - window()->resize( - std::max(window()->width(), st::groupCallWidth), - std::max(window()->height(), st::groupCallWidth)); - } - _layerBg->showBox(std::move(box), options, animated); -} - -void Panel::showLayer( - std::unique_ptr layer, - Ui::LayerOptions options, - anim::type animated) { - hideStickedTooltip(StickedTooltipHide::Unavailable); - if (window()->width() < st::groupCallWidth - || window()->height() < st::groupCallWidth) { - window()->resize( - std::max(window()->width(), st::groupCallWidth), - std::max(window()->height(), st::groupCallWidth)); - } - _layerBg->showLayer(std::move(layer), options, animated); -} - -void Panel::hideLayer(anim::type animated) { - _layerBg->hideAll(animated); -} - -bool Panel::isLayerShown() const { - return _layerBg->topShownLayer() != nullptr; -} - void Panel::kickParticipantSure(not_null participantPeer) { if (_call->conference()) { if (const auto user = participantPeer->asUser()) { @@ -1689,17 +1585,16 @@ void Panel::kickParticipantSure(not_null participantPeer) { void Panel::initLayout(ConferencePanelMigration info) { initGeometry(info); -#ifndef Q_OS_MAC - _controls->wrap.raise(); + _window->raiseControls(); - _controls->controls.layout().changes( + _window->controlsLayoutChanges( ) | rpl::start_with_next([=] { // _menuToggle geometry depends on _controls arrangement. - crl::on_main(widget(), [=] { updateControlsGeometry(); }); + crl::on_main(this, [=] { updateControlsGeometry(); }); }, lifetime()); raiseControls(); -#endif // !Q_OS_MAC + updateControlsGeometry(); } void Panel::showControls() { @@ -1714,7 +1609,7 @@ void Panel::closeBeforeDestroy() { } rpl::lifetime &Panel::lifetime() { - return window()->lifetime(); + return _lifetime; } void Panel::initGeometry(ConferencePanelMigration info) { @@ -1724,15 +1619,7 @@ void Panel::initGeometry(ConferencePanelMigration info) { const auto minHeight = _call->rtmp() ? st::groupCallHeightRtmpMin : st::groupCallHeight; - if (info.screen && !info.geometry.isEmpty()) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - window()->setScreen(info.screen); -#else // Qt >= 6.0.0 - window()->createWinId(); - window()->windowHandle()->setScreen(info.screen); -#endif // Qt < 6.0.0 - window()->setGeometry(info.geometry); - } else { + if (!info.window) { const auto center = Core::App().getPointForCallPanelCenter(); const auto width = _call->rtmp() ? st::groupCallWidthRtmp @@ -1763,7 +1650,7 @@ QRect Panel::computeTitleRect() const { #ifdef Q_OS_MAC return QRect(70, 0, width - remove - 70, 28); #else // Q_OS_MAC - const auto controls = _controls->controls.geometry(); + const auto controls = _window->controlsGeometry(); const auto right = controls.x() + controls.width() + skip; return (controls.center().x() < width / 2) ? QRect(right, 0, width - right - remove, controls.height()) @@ -1925,7 +1812,7 @@ void Panel::refreshControlsBackground() { } void Panel::refreshTitleBackground() { - if (!_fullScreenOrMaximized.current()) { + if (!_rtmpFull) { _titleBackground.destroy(); return; } else if (_titleBackground) { @@ -2070,7 +1957,7 @@ void Panel::trackControl(Ui::RpWidget *widget, rpl::lifetime &lifetime) { } void Panel::trackControlOver(not_null control, bool over) { - if (_fullScreenOrMaximized.current()) { + if (_rtmpFull) { return; } else if (_stickedTooltipClose) { if (!over) { @@ -2111,7 +1998,7 @@ void Panel::showStickedTooltip() { && callReady && _mute && !_call->mutedByAdmin() - && !_layerBg->topShownLayer()) { + && !_window->topShownLayer()) { if (_stickedTooltipClose) { // Showing already. return; @@ -2314,10 +2201,10 @@ void Panel::updateControlsGeometry() { const auto controlsOnTheLeft = true; const auto controlsPadding = 0; #else // Q_OS_MAC - const auto center = _controls->controls.geometry().center(); + const auto center = _window->controlsGeometry().center(); const auto controlsOnTheLeft = center.x() < widget()->width() / 2; - const auto controlsPadding = _controls->wrap.y(); + const auto controlsPadding = _window->controlsWrapTop(); #endif // Q_OS_MAC const auto menux = st::groupCallMenuTogglePosition.x(); const auto menuy = st::groupCallMenuTogglePosition.y(); @@ -2425,7 +2312,7 @@ void Panel::updateButtonsGeometry() { _controlsBackgroundWide->setGeometry( rect.marginsAdded(st::groupCallControlsBackMargin)); } - if (_fullScreenOrMaximized.current()) { + if (_rtmpFull) { refreshTitleGeometry(); } } else { @@ -2493,10 +2380,9 @@ void Panel::updateMembersGeometry() { _members->setVisible(!_call->rtmp()); const auto desiredHeight = _members->desiredHeight(); if (mode() == PanelMode::Wide) { - const auto full = _fullScreenOrMaximized.current(); - const auto skip = full ? 0 : st::groupCallNarrowSkip; + const auto skip = _rtmpFull ? 0 : st::groupCallNarrowSkip; const auto membersWidth = st::groupCallNarrowMembersWidth; - const auto top = full ? 0 : st::groupCallWideVideoTop; + const auto top = _rtmpFull ? 0 : st::groupCallWideVideoTop; _members->setGeometry( widget()->width() - skip - membersWidth, top, @@ -2505,7 +2391,7 @@ void Panel::updateMembersGeometry() { const auto viewportSkip = _call->rtmp() ? 0 : (skip + membersWidth); - _viewport->setGeometry(full, { + _viewport->setGeometry(_rtmpFull, { skip, top, widget()->width() - viewportSkip - 2 * skip, @@ -2654,9 +2540,8 @@ void Panel::refreshTitleGeometry() { ? st::groupCallTitleTop : (st::groupCallWideVideoTop - st::groupCallTitleLabel.style.font->height) / 2; - const auto shown = _fullScreenOrMaximized.current() - ? _wideControlsAnimation.value( - _wideControlsShown ? 1. : 0.) + const auto shown = _rtmpFull + ? _wideControlsAnimation.value(_wideControlsShown ? 1. : 0.) : 1.; const auto top = anim::interpolate( -_title->height() - st::boxRadius, @@ -2720,10 +2605,7 @@ void Panel::refreshTitleGeometry() { } else { layout(left + titleRect.width() - best); } - -#ifndef Q_OS_MAC - _controlsTop = anim::interpolate(-_controls->wrap.height(), 0, shown); -#endif // Q_OS_MAC + _window->setControlsShown(shown); } void Panel::refreshTitleColors() { @@ -2760,11 +2642,11 @@ bool Panel::handleClose() { } not_null Panel::window() const { - return _window.window(); + return _window->window(); } not_null Panel::widget() const { - return _window.widget(); + return _window->widget(); } } // namespace Calls::Group diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index 882049cb86..9110c495e9 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -7,32 +7,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "base/weak_ptr.h" -#include "base/timer.h" -#include "base/flags.h" #include "base/object_ptr.h" -#include "base/unique_qptr.h" #include "calls/group/calls_group_call.h" #include "calls/group/calls_group_common.h" #include "calls/group/calls_choose_join_as.h" #include "calls/group/ui/desktop_capture_choose_source.h" #include "ui/effects/animations.h" -#include "ui/gl/gl_window.h" -#include "ui/layers/show.h" -#include "ui/rp_widget.h" class Image; -namespace base { -class PowerSaveBlocker; -} // namespace base - namespace Data { class PhotoMedia; class GroupCall; } // namespace Data +namespace Main { +class SessionShow; +} // namespace Main + namespace Ui { +class Show; class BoxContent; class LayerWidget; enum class LayerOption; @@ -45,13 +39,13 @@ class CallMuteButton; class IconButton; class FlatLabel; class RpWidget; +class RpWindow; template class FadeWrap; template class PaddingWrap; class ScrollArea; class GenericBox; -class LayerManager; class GroupCallScheduledLeft; } // namespace Ui @@ -60,14 +54,6 @@ class Instance; struct Config; } // namespace Ui::Toast -namespace Ui::Platform { -struct SeparateTitleControls; -} // namespace Ui::Platform - -namespace Main { -class SessionShow; -} // namespace Main - namespace style { struct CallSignalBars; struct CallBodyLayout; @@ -76,6 +62,7 @@ struct CallBodyLayout; namespace Calls { struct InviteRequest; struct ConferencePanelMigration; +class Window; } // namespace Calls namespace Calls::Group { @@ -100,37 +87,20 @@ public: [[nodiscard]] bool isVisible() const; [[nodiscard]] bool isActive() const; - base::weak_ptr showToast( - const QString &text, - crl::time duration = 0); - base::weak_ptr showToast( - TextWithEntities &&text, - crl::time duration = 0); - base::weak_ptr showToast( - Ui::Toast::Config &&config); - - void showBox(object_ptr box); - void showBox( - object_ptr box, - Ui::LayerOptions options, - anim::type animated = anim::type::normal); - void showLayer( - std::unique_ptr layer, - Ui::LayerOptions options, - anim::type animated = anim::type::normal); - void hideLayer(anim::type animated = anim::type::normal); - [[nodiscard]] bool isLayerShown() const; - void migrationShowShareLink(); void migrationInviteUsers(std::vector users); void minimize(); void toggleFullScreen(); + void toggleFullScreen(bool fullscreen); void close(); void showAndActivate(); void closeBeforeDestroy(); - [[nodiscard]] std::shared_ptr uiShow(); + [[nodiscard]] std::shared_ptr sessionShow(); + [[nodiscard]] std::shared_ptr uiShow(); + + [[nodiscard]] not_null window() const; rpl::lifetime &lifetime(); @@ -148,8 +118,6 @@ private: Discarded, }; - [[nodiscard]] not_null window() const; - [[nodiscard]] PanelMode mode() const; void paint(QRect clip); @@ -237,18 +205,11 @@ private: const not_null _call; not_null _peer; - Ui::GL::Window _window; - const std::unique_ptr _layerBg; + std::shared_ptr _window; rpl::variable _mode; rpl::variable _fullScreenOrMaximized = false; bool _unpinnedMaximized = false; - -#ifndef Q_OS_MAC - rpl::variable _controlsTop = 0; - const std::unique_ptr _controls; -#endif // !Q_OS_MAC - - const std::unique_ptr _powerSaveBlocker; + bool _rtmpFull = false; rpl::lifetime _callLifetime; @@ -305,6 +266,7 @@ private: rpl::lifetime _hideControlsTimerLifetime; rpl::lifetime _peerLifetime; + rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/calls/group/calls_group_toasts.cpp b/Telegram/SourceFiles/calls/group/calls_group_toasts.cpp index 55e67be95e..584a30b551 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_toasts.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_toasts.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_panel.h" #include "data/data_peer.h" #include "data/data_group_call.h" +#include "ui/layers/show.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" #include "lang/lang_keys.h" @@ -49,7 +50,7 @@ void Toasts::setupJoinAsChanged() { return (state == State::Joined); }) | rpl::take(1); }) | rpl::flatten_latest() | rpl::start_with_next([=] { - _panel->showToast((_call->peer()->isBroadcast() + _panel->uiShow()->showToast((_call->peer()->isBroadcast() ? tr::lng_group_call_join_as_changed_channel : tr::lng_group_call_join_as_changed)( tr::now, @@ -69,7 +70,7 @@ void Toasts::setupTitleChanged() { ? peer->name() : peer->groupCall()->title(); }) | rpl::start_with_next([=](const QString &title) { - _panel->showToast((_call->peer()->isBroadcast() + _panel->uiShow()->showToast((_call->peer()->isBroadcast() ? tr::lng_group_call_title_changed_channel : tr::lng_group_call_title_changed)( tr::now, @@ -83,7 +84,8 @@ void Toasts::setupAllowedToSpeak() { _call->allowedToSpeakNotifications( ) | rpl::start_with_next([=] { if (_panel->isActive()) { - _panel->showToast(tr::lng_group_call_can_speak_here(tr::now)); + _panel->uiShow()->showToast( + tr::lng_group_call_can_speak_here(tr::now)); } else { const auto real = _call->lookupReal(); const auto name = (real && !real->title().isEmpty()) @@ -137,7 +139,7 @@ void Toasts::setupPinnedVideo() { : tr::lng_group_call_unpinned_screen); return key(tr::now, lt_user, peer->shortName()); }(); - _panel->showToast(text); + _panel->uiShow()->showToast(text); }, _lifetime); } @@ -146,7 +148,7 @@ void Toasts::setupRequestedToSpeak() { ) | rpl::combine_previous( ) | rpl::start_with_next([=](MuteState was, MuteState now) { if (was == MuteState::ForceMuted && now == MuteState::RaisedHand) { - _panel->showToast( + _panel->uiShow()->showToast( tr::lng_group_call_tooltip_raised_hand(tr::now)); } }, _lifetime); @@ -173,7 +175,7 @@ void Toasts::setupError() { } Unexpected("Error in Calls::Group::Toasts::setupErrorToasts."); }(); - _panel->showToast({ key(tr::now) }, kErrorDuration); + _panel->uiShow()->showToast({ key(tr::now) }, kErrorDuration); }, _lifetime); } diff --git a/Telegram/lib_base b/Telegram/lib_base index 720eaf44a5..419049fcbe 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 720eaf44a529da50f5277fd6874318d9a08b735a +Subproject commit 419049fcbe88c68486609232c4db7550833c74ca