tdesktop/Telegram/SourceFiles/ui/main_queue_processor.cpp
2019-10-01 23:59:46 +03:00

128 lines
3.1 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
*/
#include "ui/main_queue_processor.h"
#include "base/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::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