/* 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