127 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // This file is part of Desktop App Toolkit,
 | |
| // a set of libraries for developing nice desktop applications.
 | |
| //
 | |
| // For license and copyright information please follow this link:
 | |
| // https://github.com/desktop-app/legal/blob/master/LEGAL
 | |
| //
 | |
| #include "ui/main_queue_processor.h"
 | |
| 
 | |
| #include "base/integration.h"
 | |
| #include "ui/platform/ui_platform_utility.h"
 | |
| 
 | |
| #include <QtCore/QMutex>
 | |
| #include <QtCore/QCoreApplication>
 | |
| #include <QtGui/QtEvents>
 | |
| 
 | |
| #include <crl/crl_on_main.h>
 | |
| 
 | |
| namespace Ui {
 | |
| namespace {
 | |
| 
 | |
| constexpr auto kProcessorEvent = QEvent::Type(QEvent::User + 1);
 | |
| static_assert(kProcessorEvent < QEvent::MaxUser);
 | |
| 
 | |
| QMutex ProcessorMutex;
 | |
| MainQueueProcessor *ProcessorInstance/* = nullptr*/;
 | |
| 
 | |
| enum class ProcessState : int {
 | |
| 	Processed,
 | |
| 	FillingUp,
 | |
| 	Waiting,
 | |
| };
 | |
| 
 | |
| std::atomic<ProcessState> MainQueueProcessState/* = ProcessState(0)*/;
 | |
| void (*MainQueueProcessCallback)(void*)/* = nullptr*/;
 | |
| void *MainQueueProcessArgument/* = nullptr*/;
 | |
| 
 | |
| void PushToMainQueueGeneric(void (*callable)(void*), void *argument) {
 | |
| 	Expects(Platform::UseMainQueueGeneric());
 | |
| 
 | |
| 	auto expected = ProcessState::Processed;
 | |
| 	const auto fill = MainQueueProcessState.compare_exchange_strong(
 | |
| 		expected,
 | |
| 		ProcessState::FillingUp);
 | |
| 	if (fill) {
 | |
| 		MainQueueProcessCallback = callable;
 | |
| 		MainQueueProcessArgument = argument;
 | |
| 		MainQueueProcessState.store(ProcessState::Waiting);
 | |
| 	}
 | |
| 
 | |
| 	auto event = std::make_unique<QEvent>(kProcessorEvent);
 | |
| 
 | |
| 	QMutexLocker lock(&ProcessorMutex);
 | |
| 	if (ProcessorInstance) {
 | |
| 		QCoreApplication::postEvent(ProcessorInstance, event.release());
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void DrainMainQueueGeneric() {
 | |
| 	Expects(Platform::UseMainQueueGeneric());
 | |
| 
 | |
| 	if (MainQueueProcessState.load() != ProcessState::Waiting) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto callback = MainQueueProcessCallback;
 | |
| 	const auto argument = MainQueueProcessArgument;
 | |
| 	MainQueueProcessState.store(ProcessState::Processed);
 | |
| 
 | |
| 	callback(argument);
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| MainQueueProcessor::MainQueueProcessor() {
 | |
| 	if constexpr (Platform::UseMainQueueGeneric()) {
 | |
| 		acquire();
 | |
| 		crl::init_main_queue(PushToMainQueueGeneric);
 | |
| 	} else {
 | |
| 		crl::wrap_main_queue([](void (*callable)(void*), void *argument) {
 | |
| 			base::Integration::Instance().enterFromEventLoop([&] {
 | |
| 				callable(argument);
 | |
| 			});
 | |
| 		});
 | |
| 	}
 | |
| 
 | |
| 	crl::on_main_update_requests(
 | |
| 	) | rpl::start_with_next([] {
 | |
| 		if constexpr (Platform::UseMainQueueGeneric()) {
 | |
| 			DrainMainQueueGeneric();
 | |
| 		} else {
 | |
| 			Platform::DrainMainQueue();
 | |
| 		}
 | |
| 	}, _lifetime);
 | |
| }
 | |
| 
 | |
| bool MainQueueProcessor::event(QEvent *event) {
 | |
| 	if constexpr (Platform::UseMainQueueGeneric()) {
 | |
| 		if (event->type() == kProcessorEvent) {
 | |
| 			DrainMainQueueGeneric();
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| 	return QObject::event(event);
 | |
| }
 | |
| 
 | |
| void MainQueueProcessor::acquire() {
 | |
| 	Expects(Platform::UseMainQueueGeneric());
 | |
| 	Expects(ProcessorInstance == nullptr);
 | |
| 
 | |
| 	QMutexLocker lock(&ProcessorMutex);
 | |
| 	ProcessorInstance = this;
 | |
| }
 | |
| 
 | |
| void MainQueueProcessor::release() {
 | |
| 	Expects(Platform::UseMainQueueGeneric());
 | |
| 	Expects(ProcessorInstance == this);
 | |
| 
 | |
| 	QMutexLocker lock(&ProcessorMutex);
 | |
| 	ProcessorInstance = nullptr;
 | |
| }
 | |
| 
 | |
| MainQueueProcessor::~MainQueueProcessor() {
 | |
| 	if constexpr (Platform::UseMainQueueGeneric()) {
 | |
| 		release();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| } // namespace Ui
 | 
