82 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 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 <typename Object, typename Signal>
 | |
| auto QtSignalProducer(Object *object, Signal signal);
 | |
| 
 | |
| namespace details {
 | |
| 
 | |
| template <typename Signal>
 | |
| struct QtSignalArgument;
 | |
| 
 | |
| template <typename Class, typename Return, typename Value>
 | |
| struct QtSignalArgument<Return(Class::*)(Value)> {
 | |
| 	using type = Value;
 | |
| };
 | |
| 
 | |
| template <typename Class, typename Return>
 | |
| struct QtSignalArgument<Return(Class::*)()> {
 | |
| 	using type = void;
 | |
| };
 | |
| 
 | |
| } // namespace details
 | |
| 
 | |
| template <typename Object, typename Signal>
 | |
| auto QtSignalProducer(Object *object, Signal signal) {
 | |
| 	using Value = typename details::QtSignalArgument<Signal>::type;
 | |
| 	static constexpr auto NoArgument = std::is_same_v<Value, void>;
 | |
| 	using Produced = std::conditional_t<
 | |
| 		NoArgument,
 | |
| 		rpl::empty_value,
 | |
| 		std::remove_const_t<std::decay_t<Value>>>;
 | |
| 	const auto guarded = make_weak(object);
 | |
| 	return rpl::make_producer<Produced>([=](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<decltype(handler)>(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
 | 
