mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Replace base/task_queue with crl.
This commit is contained in:
parent
ae7e5be5cd
commit
af552fb4c0
@ -1,393 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "base/task_queue.h"
|
||||
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
auto MainThreadId = std::this_thread::get_id();
|
||||
const auto MaxThreadsCount = qMax(std::thread::hardware_concurrency(), 2U);
|
||||
|
||||
} // namespace
|
||||
|
||||
class TaskQueue::TaskQueueList {
|
||||
public:
|
||||
TaskQueueList();
|
||||
|
||||
void Register(TaskQueue *queue);
|
||||
void Unregister(TaskQueue *queue);
|
||||
bool IsInList(TaskQueue *queue) const;
|
||||
void Clear();
|
||||
bool Empty(int list_index_) const;
|
||||
TaskQueue *TakeFirst(int list_index_);
|
||||
|
||||
private:
|
||||
void Insert(TaskQueue *queue, int list_index_);
|
||||
void Remove(TaskQueue *queue, int list_index_);
|
||||
|
||||
TaskQueue *Tail() { return &tail_; }
|
||||
const TaskQueue *Tail() const { return &tail_; }
|
||||
|
||||
TaskQueue tail_ = { Type::Special, Priority::Normal };
|
||||
TaskQueue *(lists_[kQueuesListsCount]);
|
||||
|
||||
};
|
||||
|
||||
class TaskQueue::TaskThreadPool {
|
||||
struct Private {
|
||||
};
|
||||
|
||||
public:
|
||||
TaskThreadPool(const Private &) { }
|
||||
static const std::shared_ptr<TaskThreadPool> &Instance();
|
||||
|
||||
void AddQueueTask(TaskQueue *queue, Task &&task);
|
||||
void RemoveQueue(TaskQueue *queue);
|
||||
|
||||
~TaskThreadPool();
|
||||
|
||||
private:
|
||||
void ThreadFunction();
|
||||
|
||||
std::vector<std::thread> threads_;
|
||||
QMutex queues_mutex_;
|
||||
|
||||
// queues_mutex_ must be locked when working with the list.
|
||||
TaskQueueList queue_list_;
|
||||
|
||||
QWaitCondition thread_condition_;
|
||||
bool stopped_ = false;
|
||||
int tasks_in_process_ = 0;
|
||||
int background_tasks_in_process_ = 0;
|
||||
|
||||
};
|
||||
|
||||
TaskQueue::TaskQueueList::TaskQueueList() {
|
||||
for (auto &list : lists_) {
|
||||
list = &tail_;
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::TaskQueueList::Register(TaskQueue *queue) {
|
||||
Assert(!queue->SerialTaskInProcess());
|
||||
|
||||
Insert(queue, kAllQueuesList);
|
||||
if (queue->priority_ == Priority::Normal) {
|
||||
Insert(queue, kOnlyNormalQueuesList);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::TaskQueueList::Unregister(TaskQueue *queue) {
|
||||
Remove(queue, kAllQueuesList);
|
||||
if (queue->priority_ == Priority::Normal) {
|
||||
Remove(queue, kOnlyNormalQueuesList);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::TaskQueueList::Insert(TaskQueue *queue, int list_index_) {
|
||||
Assert(list_index_ < kQueuesListsCount);
|
||||
|
||||
auto tail = Tail();
|
||||
if (lists_[list_index_] == tail) {
|
||||
lists_[list_index_] = queue;
|
||||
}
|
||||
|
||||
auto &list_entry = queue->list_entries_[list_index_];
|
||||
Assert(list_entry.after == nullptr);
|
||||
if ((list_entry.before = tail->list_entries_[list_index_].before)) {
|
||||
list_entry.before->list_entries_[list_index_].after = queue;
|
||||
}
|
||||
list_entry.after = tail;
|
||||
tail->list_entries_[list_index_].before = queue;
|
||||
}
|
||||
|
||||
void TaskQueue::TaskQueueList::Remove(TaskQueue *queue, int list_index_) {
|
||||
Assert(list_index_ < kQueuesListsCount);
|
||||
|
||||
auto &list_entry = queue->list_entries_[list_index_];
|
||||
Assert(list_entry.after != nullptr);
|
||||
if (lists_[list_index_] == queue) {
|
||||
lists_[list_index_] = list_entry.after;
|
||||
} else {
|
||||
Assert(list_entry.before != nullptr);
|
||||
list_entry.before->list_entries_[list_index_].after = list_entry.after;
|
||||
}
|
||||
list_entry.after->list_entries_[list_index_].before = list_entry.before;
|
||||
list_entry.before = list_entry.after = nullptr;
|
||||
}
|
||||
|
||||
bool TaskQueue::TaskQueueList::IsInList(TaskQueue *queue) const {
|
||||
if (queue->list_entries_[kAllQueuesList].after) {
|
||||
return true;
|
||||
}
|
||||
Assert(queue->list_entries_[kOnlyNormalQueuesList].after == nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
void TaskQueue::TaskQueueList::Clear() {
|
||||
auto tail = Tail();
|
||||
for (int i = 0; i < kQueuesListsCount; ++i) {
|
||||
for (auto j = lists_[i], next = j; j != tail; j = next) {
|
||||
auto &list_entry = j->list_entries_[i];
|
||||
next = list_entry.after;
|
||||
list_entry.before = list_entry.after = nullptr;
|
||||
}
|
||||
lists_[i] = tail;
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskQueue::TaskQueueList::Empty(int list_index_) const {
|
||||
Assert(list_index_ < kQueuesListsCount);
|
||||
|
||||
auto list = lists_[list_index_];
|
||||
Assert(list != nullptr);
|
||||
return (list->list_entries_[list_index_].after == nullptr);
|
||||
}
|
||||
|
||||
TaskQueue *TaskQueue::TaskQueueList::TakeFirst(int list_index_) {
|
||||
Assert(!Empty(list_index_));
|
||||
|
||||
auto queue = lists_[list_index_];
|
||||
Unregister(queue);
|
||||
// log_msgs.push_back("Unregistered from list in TakeFirst");
|
||||
return queue;
|
||||
}
|
||||
|
||||
void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) {
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
|
||||
queue->tasks_.push_back(std::move(task));
|
||||
auto list_was_empty = queue_list_.Empty(kAllQueuesList);
|
||||
auto threads_count = threads_.size();
|
||||
auto all_threads_processing = (threads_count == tasks_in_process_);
|
||||
auto some_threads_are_vacant = !all_threads_processing && list_was_empty;
|
||||
auto will_create_thread = !some_threads_are_vacant && (threads_count < MaxThreadsCount);
|
||||
|
||||
if (!queue->SerialTaskInProcess()) {
|
||||
if (!queue_list_.IsInList(queue)) {
|
||||
queue_list_.Register(queue);
|
||||
}
|
||||
}
|
||||
if (will_create_thread) {
|
||||
threads_.emplace_back([this]() {
|
||||
ThreadFunction();
|
||||
});
|
||||
} else if (some_threads_are_vacant) {
|
||||
Assert(threads_count > tasks_in_process_);
|
||||
thread_condition_.wakeOne();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::TaskThreadPool::RemoveQueue(TaskQueue *queue) {
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
if (queue_list_.IsInList(queue)) {
|
||||
queue_list_.Unregister(queue);
|
||||
}
|
||||
if (queue->destroyed_flag_) {
|
||||
*queue->destroyed_flag_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
TaskQueue::TaskThreadPool::~TaskThreadPool() {
|
||||
{
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
queue_list_.Clear();
|
||||
stopped_ = true;
|
||||
}
|
||||
thread_condition_.wakeAll();
|
||||
for (auto &thread : threads_) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<TaskQueue::TaskThreadPool> &TaskQueue::TaskThreadPool::Instance() { // static
|
||||
static auto Pool = std::make_shared<TaskThreadPool>(Private());
|
||||
return Pool;
|
||||
}
|
||||
|
||||
void TaskQueue::TaskThreadPool::ThreadFunction() {
|
||||
// Flag marking that the previous processed task was
|
||||
// with a Background priority. We count all the background
|
||||
// tasks being processed.
|
||||
bool background_task = false;
|
||||
|
||||
// Saved serial queue pointer. When we process a serial
|
||||
// queue task we don't return the queue to the list until
|
||||
// the task is processed and we return it on the next cycle.
|
||||
TaskQueue *serial_queue = nullptr;
|
||||
bool serial_queue_destroyed = false;
|
||||
bool task_was_processed = false;
|
||||
while (true) {
|
||||
Task task;
|
||||
{
|
||||
QMutexLocker lock(&queues_mutex_);
|
||||
|
||||
// Finish the previous task processing.
|
||||
if (task_was_processed) {
|
||||
--tasks_in_process_;
|
||||
}
|
||||
if (background_task) {
|
||||
--background_tasks_in_process_;
|
||||
background_task = false;
|
||||
}
|
||||
if (serial_queue) {
|
||||
if (!serial_queue_destroyed) {
|
||||
serial_queue->destroyed_flag_ = nullptr;
|
||||
if (!serial_queue->tasks_.empty()) {
|
||||
queue_list_.Register(serial_queue);
|
||||
}
|
||||
}
|
||||
serial_queue = nullptr;
|
||||
serial_queue_destroyed = false;
|
||||
}
|
||||
|
||||
// Wait for a task to appear in the queues list.
|
||||
while (queue_list_.Empty(kAllQueuesList)) {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
thread_condition_.wait(&queues_mutex_);
|
||||
}
|
||||
|
||||
// Select a task we will be processing.
|
||||
auto processing_background = (background_tasks_in_process_ > 0);
|
||||
auto take_only_normal = processing_background && !queue_list_.Empty(kOnlyNormalQueuesList);
|
||||
auto take_from_list_ = take_only_normal ? kOnlyNormalQueuesList : kAllQueuesList;
|
||||
auto queue = queue_list_.TakeFirst(take_from_list_);
|
||||
|
||||
Assert(!queue->tasks_.empty());
|
||||
|
||||
task = std::move(queue->tasks_.front());
|
||||
queue->tasks_.pop_front();
|
||||
|
||||
if (queue->type_ == Type::Serial) {
|
||||
// Serial queues are returned in the list for processing
|
||||
// only after the task is finished.
|
||||
serial_queue = queue;
|
||||
Assert(serial_queue->destroyed_flag_ == nullptr);
|
||||
serial_queue->destroyed_flag_ = &serial_queue_destroyed;
|
||||
} else if (!queue->tasks_.empty()) {
|
||||
queue_list_.Register(queue);
|
||||
}
|
||||
|
||||
++tasks_in_process_;
|
||||
task_was_processed = true;
|
||||
if (queue->priority_ == Priority::Background) {
|
||||
++background_tasks_in_process_;
|
||||
background_task = true;
|
||||
}
|
||||
}
|
||||
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
TaskQueue::TaskQueue(Type type, Priority priority)
|
||||
: type_(type)
|
||||
, priority_(priority) {
|
||||
if (type_ != Type::Main && type_ != Type::Special) {
|
||||
weak_thread_pool_ = TaskThreadPool::Instance();
|
||||
}
|
||||
}
|
||||
|
||||
TaskQueue::~TaskQueue() {
|
||||
if (type_ != Type::Main && type_ != Type::Special) {
|
||||
if (auto thread_pool = weak_thread_pool_.lock()) {
|
||||
thread_pool->RemoveQueue(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::Put(Task &&task) {
|
||||
if (type_ == Type::Main) {
|
||||
QMutexLocker lock(&tasks_mutex_);
|
||||
tasks_.push_back(std::move(task));
|
||||
|
||||
Sandbox::MainThreadTaskAdded();
|
||||
} else {
|
||||
Assert(type_ != Type::Special);
|
||||
TaskThreadPool::Instance()->AddQueueTask(this, std::move(task));
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::ProcessMainTasks() { // static
|
||||
Assert(std::this_thread::get_id() == MainThreadId);
|
||||
|
||||
while (ProcessOneMainTask()) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskQueue::ProcessMainTasks(TimeMs max_time_spent) { // static
|
||||
Assert(std::this_thread::get_id() == MainThreadId);
|
||||
|
||||
auto start_time = getms();
|
||||
while (ProcessOneMainTask()) {
|
||||
if (getms() >= start_time + max_time_spent) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskQueue::ProcessOneMainTask() { // static
|
||||
Task task;
|
||||
{
|
||||
QMutexLocker lock(&Main().tasks_mutex_);
|
||||
auto &tasks = Main().tasks_;
|
||||
if (tasks.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
task = std::move(tasks.front());
|
||||
tasks.pop_front();
|
||||
}
|
||||
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskQueue::IsMyThread() const {
|
||||
if (type_ == Type::Main) {
|
||||
return (std::this_thread::get_id() == MainThreadId);
|
||||
}
|
||||
Assert(type_ != Type::Special);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default queues.
|
||||
TaskQueue &TaskQueue::Main() { // static
|
||||
static TaskQueue MainQueue { Type::Main, Priority::Normal };
|
||||
return MainQueue;
|
||||
}
|
||||
|
||||
TaskQueue &TaskQueue::Normal() { // static
|
||||
static TaskQueue NormalQueue { Type::Concurrent, Priority::Normal };
|
||||
return NormalQueue;
|
||||
}
|
||||
|
||||
TaskQueue &TaskQueue::Background() { // static
|
||||
static TaskQueue BackgroundQueue { Type::Concurrent, Priority::Background };
|
||||
return BackgroundQueue;
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace base {
|
||||
|
||||
using Task = lambda_once<void()>;
|
||||
|
||||
// An attempt to create/use a TaskQueue or one of the default queues
|
||||
// after the main() has returned leads to an undefined behaviour.
|
||||
class TaskQueue {
|
||||
enum class Type {
|
||||
Main, // Unique queue for main thread tasks.
|
||||
Serial,
|
||||
Concurrent,
|
||||
Special, // Unique special queue for thread pool lists terminal item.
|
||||
};
|
||||
|
||||
public:
|
||||
enum class Priority {
|
||||
Normal,
|
||||
Background,
|
||||
};
|
||||
|
||||
// Creating custom serial queues.
|
||||
TaskQueue(Priority priority) : TaskQueue(Type::Serial, priority) {
|
||||
}
|
||||
|
||||
// Default main and two concurrent queues.
|
||||
static TaskQueue &Main();
|
||||
static TaskQueue &Normal();
|
||||
static TaskQueue &Background();
|
||||
|
||||
void Put(Task &&task);
|
||||
|
||||
static void ProcessMainTasks();
|
||||
static void ProcessMainTasks(TimeMs max_time_spent);
|
||||
|
||||
~TaskQueue();
|
||||
|
||||
private:
|
||||
static bool ProcessOneMainTask();
|
||||
|
||||
TaskQueue(Type type, Priority priority);
|
||||
|
||||
bool IsMyThread() const;
|
||||
bool SerialTaskInProcess() const {
|
||||
return (destroyed_flag_ != nullptr);
|
||||
}
|
||||
|
||||
const Type type_;
|
||||
const Priority priority_;
|
||||
|
||||
std::deque<Task> tasks_;
|
||||
QMutex tasks_mutex_; // Only for the main queue.
|
||||
|
||||
// Only for the other queues, not main.
|
||||
class TaskThreadPool;
|
||||
std::weak_ptr<TaskThreadPool> weak_thread_pool_;
|
||||
|
||||
class TaskQueueList;
|
||||
|
||||
struct TaskQueueListEntry {
|
||||
TaskQueue *before = nullptr;
|
||||
TaskQueue *after = nullptr;
|
||||
};
|
||||
|
||||
// Thread pool queues linked list.
|
||||
static constexpr int kAllQueuesList = 0;
|
||||
|
||||
// Thread pool queues linked list with excluded Background queues.
|
||||
static constexpr int kOnlyNormalQueuesList = 1;
|
||||
|
||||
static constexpr int kQueuesListsCount = 2;
|
||||
TaskQueueListEntry list_entries_[kQueuesListsCount];
|
||||
|
||||
// Only for Serial queues: non-null value means a task is currently processed.
|
||||
bool *destroyed_flag_ = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace base
|
@ -280,6 +280,55 @@ weak_ptr<T> make_weak(const std::weak_ptr<T> &value) {
|
||||
|
||||
} // namespace base
|
||||
|
||||
namespace crl {
|
||||
|
||||
template <typename T, typename Enable>
|
||||
struct guard_traits;
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<base::weak_ptr<T>, void> {
|
||||
static base::weak_ptr<T> create(const base::weak_ptr<T> &value) {
|
||||
return value;
|
||||
}
|
||||
static base::weak_ptr<T> create(base::weak_ptr<T> &&value) {
|
||||
return std::move(value);
|
||||
}
|
||||
static bool check(const base::weak_ptr<T> &guard) {
|
||||
return guard.get() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<
|
||||
T*,
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<base::has_weak_ptr, std::remove_cv_t<T>>>> {
|
||||
static base::weak_ptr<T> create(T *value) {
|
||||
return value;
|
||||
}
|
||||
static bool check(const base::weak_ptr<T> &guard) {
|
||||
return guard.get() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<
|
||||
gsl::not_null<T*>,
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<base::has_weak_ptr, std::remove_cv_t<T>>>> {
|
||||
static base::weak_ptr<T> create(gsl::not_null<T*> value) {
|
||||
return value.get();
|
||||
}
|
||||
static bool check(const base::weak_ptr<T> &guard) {
|
||||
return guard.get() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#ifdef QT_VERSION
|
||||
template <typename Lambda>
|
||||
inline void InvokeQueued(const base::has_weak_ptr *context, Lambda &&lambda) {
|
||||
|
@ -37,7 +37,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "apiwrap.h"
|
||||
#include "observer_peer.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "window/main_window.h"
|
||||
|
||||
namespace Calls {
|
||||
@ -425,10 +424,8 @@ void Panel::showControls() {
|
||||
|
||||
void Panel::destroyDelayed() {
|
||||
hide();
|
||||
base::TaskQueue::Main().Put([weak = QPointer<Panel>(this)] {
|
||||
if (weak) {
|
||||
delete weak.data();
|
||||
}
|
||||
crl::on_main(this, [=] {
|
||||
delete this;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "mainwindow.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "messenger.h"
|
||||
|
||||
bool filedialogGetSaveFile(
|
||||
@ -99,13 +98,13 @@ QString filedialogNextFilename(
|
||||
namespace File {
|
||||
|
||||
void OpenEmailLink(const QString &email) {
|
||||
base::TaskQueue::Main().Put([email] {
|
||||
crl::on_main([=] {
|
||||
Platform::File::UnsafeOpenEmailLink(email);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenWith(const QString &filepath, QPoint menuPosition) {
|
||||
base::TaskQueue::Main().Put([filepath, menuPosition] {
|
||||
crl::on_main([=] {
|
||||
if (!Platform::File::UnsafeShowOpenWithDropdown(filepath, menuPosition)) {
|
||||
if (!Platform::File::UnsafeShowOpenWith(filepath)) {
|
||||
Platform::File::UnsafeLaunch(filepath);
|
||||
@ -115,13 +114,13 @@ void OpenWith(const QString &filepath, QPoint menuPosition) {
|
||||
}
|
||||
|
||||
void Launch(const QString &filepath) {
|
||||
base::TaskQueue::Main().Put([filepath] {
|
||||
crl::on_main([=] {
|
||||
Platform::File::UnsafeLaunch(filepath);
|
||||
});
|
||||
}
|
||||
|
||||
void ShowInFolder(const QString &filepath) {
|
||||
base::TaskQueue::Main().Put([filepath] {
|
||||
crl::on_main([=] {
|
||||
Platform::File::UnsafeShowInFolder(filepath);
|
||||
});
|
||||
}
|
||||
@ -147,7 +146,7 @@ void GetOpenPath(
|
||||
const QString &filter,
|
||||
base::lambda<void(OpenResult &&result)> callback,
|
||||
base::lambda<void()> failed) {
|
||||
base::TaskQueue::Main().Put([=] {
|
||||
crl::on_main([=] {
|
||||
auto files = QStringList();
|
||||
auto remoteContent = QByteArray();
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
@ -178,7 +177,7 @@ void GetOpenPaths(
|
||||
const QString &filter,
|
||||
base::lambda<void(OpenResult &&result)> callback,
|
||||
base::lambda<void()> failed) {
|
||||
base::TaskQueue::Main().Put([=] {
|
||||
crl::on_main([=] {
|
||||
auto files = QStringList();
|
||||
auto remoteContent = QByteArray();
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
@ -206,7 +205,7 @@ void GetWritePath(
|
||||
const QString &initialPath,
|
||||
base::lambda<void(QString &&result)> callback,
|
||||
base::lambda<void()> failed) {
|
||||
base::TaskQueue::Main().Put([=] {
|
||||
crl::on_main([=] {
|
||||
auto file = QString();
|
||||
if (filedialogGetSaveFile(file, caption, filter, initialPath)) {
|
||||
if (callback) {
|
||||
@ -223,7 +222,7 @@ void GetFolder(
|
||||
const QString &initialPath,
|
||||
base::lambda<void(QString &&result)> callback,
|
||||
base::lambda<void()> failed) {
|
||||
base::TaskQueue::Main().Put([=] {
|
||||
crl::on_main([=] {
|
||||
auto files = QStringList();
|
||||
auto remoteContent = QByteArray();
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
|
@ -35,7 +35,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "window/layer_widget.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/observer.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "history/history_media.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
@ -508,20 +507,7 @@ void WorkingDirReady() {
|
||||
}
|
||||
}
|
||||
|
||||
object_ptr<SingleQueuedInvokation> MainThreadTaskHandler = { nullptr };
|
||||
|
||||
void MainThreadTaskAdded() {
|
||||
if (!started()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MainThreadTaskHandler->call();
|
||||
}
|
||||
|
||||
void start() {
|
||||
MainThreadTaskHandler.create([] {
|
||||
base::TaskQueue::ProcessMainTasks();
|
||||
});
|
||||
SandboxData = std::make_unique<internal::Data>();
|
||||
}
|
||||
|
||||
@ -531,7 +517,6 @@ bool started() {
|
||||
|
||||
void finish() {
|
||||
SandboxData.reset();
|
||||
MainThreadTaskHandler.destroy();
|
||||
}
|
||||
|
||||
uint64 UserTag() {
|
||||
|
@ -111,10 +111,8 @@ void ActivateWindowDelayed(not_null<Window::Controller*> controller) {
|
||||
const auto window = controller->window();
|
||||
const auto weak = make_weak(window.get());
|
||||
window->activateWindow();
|
||||
crl::on_main([=] {
|
||||
if (weak) {
|
||||
weak->activateWindow();
|
||||
}
|
||||
crl::on_main(window, [=] {
|
||||
window->activateWindow();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/themes/window_theme_warning.h"
|
||||
#include "window/window_main_menu.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "auth_session.h"
|
||||
#include "window/window_controller.h"
|
||||
|
||||
@ -535,24 +534,23 @@ void MainWindow::themeUpdated(const Window::Theme::BackgroundUpdate &data) {
|
||||
_testingThemeWarning->setGeometry(rect());
|
||||
_testingThemeWarning->setHiddenCallback([this] { _testingThemeWarning.destroyDelayed(); });
|
||||
}
|
||||
|
||||
base::TaskQueue::Main().Put(base::lambda_guarded(this, [this] {
|
||||
crl::on_main(this, [=] {
|
||||
if (_testingThemeWarning) {
|
||||
_testingThemeWarning->showAnimated();
|
||||
}
|
||||
}));
|
||||
});
|
||||
} else if (data.type == Type::RevertingTheme || data.type == Type::ApplyingTheme) {
|
||||
if (_testingThemeWarning) {
|
||||
if (_testingThemeWarning->isHidden()) {
|
||||
_testingThemeWarning.destroy();
|
||||
} else {
|
||||
base::TaskQueue::Main().Put(base::lambda_guarded(this, [this] {
|
||||
crl::on_main(this, [=] {
|
||||
if (_testingThemeWarning) {
|
||||
_testingThemeWarning->hideAnimated();
|
||||
_testingThemeWarning = nullptr;
|
||||
}
|
||||
setInnerFocus();
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "media/media_audio_loaders.h"
|
||||
#include "media/media_audio_track.h"
|
||||
#include "platform/platform_audio.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "messenger.h"
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
@ -230,27 +230,35 @@ bool AttachToDevice() {
|
||||
emit m->faderOnTimer();
|
||||
}
|
||||
|
||||
base::TaskQueue::Main().Put([] {
|
||||
Current().reattachTracks();
|
||||
crl::on_main([] {
|
||||
if (Messenger::InstancePointer()) {
|
||||
Current().reattachTracks();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScheduleDetachFromDeviceSafe() {
|
||||
base::TaskQueue::Main().Put([] {
|
||||
Current().scheduleDetachFromDevice();
|
||||
crl::on_main([] {
|
||||
if (Messenger::InstancePointer()) {
|
||||
Current().scheduleDetachFromDevice();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ScheduleDetachIfNotUsedSafe() {
|
||||
base::TaskQueue::Main().Put([] {
|
||||
Current().scheduleDetachIfNotUsed();
|
||||
crl::on_main([] {
|
||||
if (Messenger::InstancePointer()) {
|
||||
Current().scheduleDetachIfNotUsed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void StopDetachIfNotUsedSafe() {
|
||||
base::TaskQueue::Main().Put([] {
|
||||
Current().stopDetachIfNotUsed();
|
||||
crl::on_main([] {
|
||||
if (Messenger::InstancePointer()) {
|
||||
Current().stopDetachIfNotUsed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "history/history_media_types.h"
|
||||
#include "window/themes/window_theme_preview.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "messenger.h"
|
||||
@ -1708,38 +1707,43 @@ void MediaView::initThemePreview() {
|
||||
auto &location = _doc->location();
|
||||
if (!location.isEmpty() && location.accessEnable()) {
|
||||
_themePreviewShown = true;
|
||||
auto path = _doc->location().name();
|
||||
auto id = _themePreviewId = rand_value<uint64>();
|
||||
auto ready = base::lambda_guarded(this, [this, id](std::unique_ptr<Window::Theme::Preview> result) {
|
||||
if (id != _themePreviewId) {
|
||||
return;
|
||||
}
|
||||
_themePreviewId = 0;
|
||||
_themePreview = std::move(result);
|
||||
if (_themePreview) {
|
||||
_themeApply.create(this, langFactory(lng_theme_preview_apply), st::themePreviewApplyButton);
|
||||
_themeApply->show();
|
||||
_themeApply->setClickedCallback([this] {
|
||||
auto preview = std::move(_themePreview);
|
||||
close();
|
||||
Window::Theme::Apply(std::move(preview));
|
||||
});
|
||||
_themeCancel.create(this, langFactory(lng_cancel), st::themePreviewCancelButton);
|
||||
_themeCancel->show();
|
||||
_themeCancel->setClickedCallback([this] { close(); });
|
||||
updateControls();
|
||||
}
|
||||
update();
|
||||
});
|
||||
|
||||
Window::Theme::CurrentData current;
|
||||
current.backgroundId = Window::Theme::Background()->id();
|
||||
current.backgroundImage = Window::Theme::Background()->pixmap();
|
||||
current.backgroundTiled = Window::Theme::Background()->tile();
|
||||
|
||||
const auto path = _doc->location().name();
|
||||
const auto id = _themePreviewId = rand_value<uint64>();
|
||||
const auto weak = make_weak(this);
|
||||
crl::async([=] {
|
||||
auto preview = Window::Theme::GeneratePreview(path, current);
|
||||
crl::on_main([ready, result = std::move(preview)]() mutable {
|
||||
ready(std::move(result));
|
||||
crl::on_main(weak, [=, result = std::move(preview)]() mutable {
|
||||
if (id != _themePreviewId) {
|
||||
return;
|
||||
}
|
||||
_themePreviewId = 0;
|
||||
_themePreview = std::move(result);
|
||||
if (_themePreview) {
|
||||
_themeApply.create(
|
||||
this,
|
||||
langFactory(lng_theme_preview_apply),
|
||||
st::themePreviewApplyButton);
|
||||
_themeApply->show();
|
||||
_themeApply->setClickedCallback([this] {
|
||||
auto preview = std::move(_themePreview);
|
||||
close();
|
||||
Window::Theme::Apply(std::move(preview));
|
||||
});
|
||||
_themeCancel.create(
|
||||
this,
|
||||
langFactory(lng_cancel),
|
||||
st::themePreviewCancelButton);
|
||||
_themeCancel->show();
|
||||
_themeCancel->setClickedCallback([this] { close(); });
|
||||
updateControls();
|
||||
}
|
||||
update();
|
||||
});
|
||||
});
|
||||
location.accessDisable();
|
||||
|
@ -24,7 +24,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "platform/linux/linux_libnotify.h"
|
||||
#include "platform/linux/linux_libs.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/task_queue.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
@ -203,10 +202,9 @@ private:
|
||||
MsgId msgId = 0;
|
||||
};
|
||||
static void performOnMainQueue(NotificationDataStruct *data, base::lambda_once<void(Manager *manager)> task) {
|
||||
base::TaskQueue::Main().Put([weak = data->weak, task = std::move(task)]() mutable {
|
||||
if (auto strong = weak.lock()) {
|
||||
task(*strong);
|
||||
}
|
||||
const auto weak = data->weak;
|
||||
crl::on_main(weak, [=, task = std::move(task)]() mutable {
|
||||
task(*weak.lock());
|
||||
});
|
||||
}
|
||||
static void notificationDataFree(gpointer data) {
|
||||
|
@ -24,7 +24,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "platform/mac/mac_utilities.h"
|
||||
#include "styles/style_window.h"
|
||||
#include "mainwindow.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "base/variant.h"
|
||||
|
||||
#include <thread>
|
||||
@ -87,7 +86,7 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm);
|
||||
auto notificationManagerId = managerIdObject ? [managerIdObject unsignedLongLongValue] : 0ULL;
|
||||
DEBUG_LOG(("Received notification with instance %1, mine: %2").arg(notificationManagerId).arg(_managerId));
|
||||
if (notificationManagerId != _managerId) { // other app instance notification
|
||||
base::TaskQueue::Main().Put([] {
|
||||
crl::on_main([] {
|
||||
// Usually we show and activate main window when the application
|
||||
// is activated (receives applicationDidBecomeActive: notification).
|
||||
//
|
||||
@ -112,17 +111,15 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm);
|
||||
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
|
||||
auto notificationMsgId = msgObject ? [msgObject intValue] : 0;
|
||||
if (notification.activationType == NSUserNotificationActivationTypeReplied) {
|
||||
auto notificationReply = QString::fromUtf8([[[notification response] string] UTF8String]);
|
||||
base::TaskQueue::Main().Put([manager = _manager, notificationPeerId, notificationMsgId, notificationReply] {
|
||||
if (manager) {
|
||||
manager->notificationReplied(notificationPeerId, notificationMsgId, notificationReply);
|
||||
}
|
||||
const auto notificationReply = QString::fromUtf8([[[notification response] string] UTF8String]);
|
||||
const auto manager = _manager;
|
||||
crl::on_main(manager, [=] {
|
||||
manager->notificationReplied(notificationPeerId, notificationMsgId, notificationReply);
|
||||
});
|
||||
} else if (notification.activationType == NSUserNotificationActivationTypeContentsClicked) {
|
||||
base::TaskQueue::Main().Put([manager = _manager, notificationPeerId, notificationMsgId] {
|
||||
if (manager) {
|
||||
manager->notificationActivated(notificationPeerId, notificationMsgId);
|
||||
}
|
||||
const auto manager = _manager;
|
||||
crl::on_main(manager, [=] {
|
||||
manager->notificationActivated(notificationPeerId, notificationMsgId);
|
||||
});
|
||||
}
|
||||
|
||||
@ -214,9 +211,9 @@ Manager::Private::Private(Manager *manager)
|
||||
subscribe(Global::RefWorkMode(), [this](DBIWorkMode mode) {
|
||||
// We need to update the delegate _after_ the tray icon change was done in Qt.
|
||||
// Because Qt resets the delegate.
|
||||
base::TaskQueue::Main().Put(base::lambda_guarded(this, [this] {
|
||||
crl::on_main(this, [=] {
|
||||
updateDelegate();
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "platform/win/windows_event_filter.h"
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "mainwindow.h"
|
||||
#include "base/task_queue.h"
|
||||
|
||||
#include <Shobjidl.h>
|
||||
#include <shellapi.h>
|
||||
@ -226,10 +225,9 @@ public:
|
||||
~ToastEventHandler() = default;
|
||||
|
||||
void performOnMainQueue(base::lambda_once<void(Manager *manager)> task) {
|
||||
base::TaskQueue::Main().Put([weak = _weak, task = std::move(task)]() mutable {
|
||||
if (auto strong = weak.lock()) {
|
||||
task(*strong);
|
||||
}
|
||||
const auto weak = _weak;
|
||||
crl::on_main(weak, [=, task = std::move(task)]() mutable {
|
||||
task(*weak.lock());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "history/history_location_manager.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "passcodewidget.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "core/crash_reports.h"
|
||||
|
||||
#include <Shobjidl.h>
|
||||
|
@ -21,7 +21,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/storage_media_prepare.h"
|
||||
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "storage/localimageloader.h"
|
||||
|
||||
namespace Storage {
|
||||
@ -58,8 +57,8 @@ bool PrepareAlbumMediaIsWaiting(
|
||||
QSemaphore &semaphore,
|
||||
PreparedFile &file,
|
||||
int previewWidth) {
|
||||
// Use some special thread queue, like a separate QThreadPool.
|
||||
base::TaskQueue::Normal().Put([&, previewWidth] {
|
||||
// TODO: Use some special thread queue, like a separate QThreadPool.
|
||||
crl::async([=, &semaphore, &file] {
|
||||
const auto guard = gsl::finally([&] { semaphore.release(); });
|
||||
if (!file.path.isEmpty()) {
|
||||
file.mime = mimeTypeForFile(QFileInfo(file.path)).name();
|
||||
|
@ -21,7 +21,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/storage_shared_media.h"
|
||||
|
||||
#include <rpl/map.h>
|
||||
#include "base/task_queue.h"
|
||||
|
||||
namespace Storage {
|
||||
|
||||
|
@ -20,8 +20,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "storage/storage_user_photos.h"
|
||||
|
||||
#include "base/task_queue.h"
|
||||
|
||||
namespace Storage {
|
||||
|
||||
void UserPhotos::List::addNew(PhotoId photoId) {
|
||||
|
@ -35,7 +35,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
#include "base/parse_helper.h"
|
||||
#include "base/task_queue.h"
|
||||
#include "base/zlib_help.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "core/file_utilities.h"
|
||||
@ -718,7 +717,9 @@ Editor::Editor(QWidget*, const QString &path)
|
||||
|
||||
// This could be from inner->_context observable notification.
|
||||
// We should not destroy it while iterating in subscribers.
|
||||
base::TaskQueue::Main().Put(base::lambda_guarded(this, [this] { closeEditor(); }));
|
||||
crl::on_main(this, [=] {
|
||||
closeEditor();
|
||||
});
|
||||
});
|
||||
_inner->setFocusCallback([this] {
|
||||
App::CallDelayed(2 * st::boxDuration, this, [this] { _select->setInnerFocus(); });
|
||||
|
2
Telegram/ThirdParty/crl
vendored
2
Telegram/ThirdParty/crl
vendored
@ -1 +1 @@
|
||||
Subproject commit 9e11a5c9291760d03df559d03d81fa7afdd0a46d
|
||||
Subproject commit 705a5fd6166fd577d6a95cef9d74f7aa0c4ec3ed
|
@ -52,6 +52,7 @@
|
||||
'<(crl_src_loc)/common/crl_common_list.h',
|
||||
'<(crl_src_loc)/common/crl_common_on_main.cpp',
|
||||
'<(crl_src_loc)/common/crl_common_on_main.h',
|
||||
'<(crl_src_loc)/common/crl_common_on_main_guarded.h',
|
||||
'<(crl_src_loc)/common/crl_common_queue.cpp',
|
||||
'<(crl_src_loc)/common/crl_common_queue.h',
|
||||
'<(crl_src_loc)/common/crl_common_sync.h',
|
||||
|
@ -22,8 +22,6 @@
|
||||
<(src_loc)/base/qthelp_url.h
|
||||
<(src_loc)/base/runtime_composer.cpp
|
||||
<(src_loc)/base/runtime_composer.h
|
||||
<(src_loc)/base/task_queue.cpp
|
||||
<(src_loc)/base/task_queue.h
|
||||
<(src_loc)/base/timer.cpp
|
||||
<(src_loc)/base/timer.h
|
||||
<(src_loc)/base/type_traits.h
|
||||
|
Loading…
Reference in New Issue
Block a user