diff --git a/Telegram/SourceFiles/core/qt_signal_producer.h b/Telegram/SourceFiles/core/qt_signal_producer.h new file mode 100644 index 0000000000..fa78b1e0e0 --- /dev/null +++ b/Telegram/SourceFiles/core/qt_signal_producer.h @@ -0,0 +1,82 @@ +/* +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 "core/sandbox.h" + +namespace Core { + +// This method allows to create an rpl::producer from a Qt object +// and a signal with none or one reported value. +// +// QtSignalProducer(qtWindow, &QWindow::activeChanged) | rpl::start_ +// +// This producer values construct a custom event loop leave point. +// This means that all postponeCall's will be invoked right after +// the value processing by the current consumer finishes. +template +auto QtSignalProducer(Object *object, Signal signal); + +namespace details { + +template +struct QtSignalArgument; + +template +struct QtSignalArgument { + using type = Value; +}; + +template +struct QtSignalArgument { + using type = void; +}; + +} // namespace details + +template +auto QtSignalProducer(Object *object, Signal signal) { + using Value = typename details::QtSignalArgument::type; + static constexpr auto NoArgument = std::is_same_v; + using Produced = std::conditional_t< + NoArgument, + rpl::empty_value, + std::remove_const_t>>; + const auto guarded = make_weak(object); + return rpl::make_producer([=](auto consumer) { + if (!guarded) { + return rpl::lifetime(); + } + const auto connect = [&](auto &&handler) { + const auto listener = new QObject(guarded.data()); + QObject::connect( + guarded, + signal, + listener, + std::forward(handler)); + const auto weak = make_weak(listener); + return rpl::lifetime([=] { + if (weak) { + delete weak; + } + }); + }; + auto put = [=](const Produced &value) { + Sandbox::Instance().customEnterFromEventLoop([&] { + consumer.put_next_copy(value); + }); + }; + if constexpr (NoArgument) { + return connect([put = std::move(put)] { put({}); }); + } else { + return connect(std::move(put)); + } + }); +} + +} // namespace Core