Fix postponed calls from crl::on_main() on macOS.

In libdispatch crl::on_main() implementation we bypass Application::notify() frame.
So we handle event loop nesting control manually by wrapping all invokations done
through crl::on_main() with the same methods we do from Application::notify().
This commit is contained in:
John Preston 2018-12-27 13:34:12 +04:00
parent d17c985bcb
commit d539d9b5d2
4 changed files with 45 additions and 21 deletions

View File

@ -416,12 +416,11 @@ void Application::postponeCall(FnMut<void()> &&callable) {
});
}
bool Application::notify(QObject *receiver, QEvent *e) {
if (QThread::currentThreadId() != _mainThreadId) {
return QApplication::notify(receiver, e);
}
void Application::incrementEventNestingLevel() {
++_eventNestingLevel;
const auto result = QApplication::notify(receiver, e);
}
void Application::decrementEventNestingLevel() {
if (_eventNestingLevel == _loopNestingLevel) {
_loopNestingLevel = _previousLoopNestingLevels.back();
_previousLoopNestingLevels.pop_back();
@ -429,7 +428,22 @@ bool Application::notify(QObject *receiver, QEvent *e) {
const auto processTillLevel = _eventNestingLevel - 1;
processPostponedCalls(processTillLevel);
_eventNestingLevel = processTillLevel;
return result;
}
void Application::registerEnterFromEventLoop() {
if (_eventNestingLevel > _loopNestingLevel) {
_previousLoopNestingLevels.push_back(_loopNestingLevel);
_loopNestingLevel = _eventNestingLevel;
}
}
bool Application::notify(QObject *receiver, QEvent *e) {
if (QThread::currentThreadId() != _mainThreadId) {
return QApplication::notify(receiver, e);
}
const auto wrap = createEventNestingLevel();
return QApplication::notify(receiver, e);
}
void Application::processPostponedCalls(int level) {
@ -448,10 +462,7 @@ bool Application::nativeEventFilter(
const QByteArray &eventType,
void *message,
long *result) {
if (_eventNestingLevel > _loopNestingLevel) {
_previousLoopNestingLevels.push_back(_loopNestingLevel);
_loopNestingLevel = _eventNestingLevel;
}
registerEnterFromEventLoop();
return false;
}

View File

@ -28,6 +28,11 @@ public:
void postponeCall(FnMut<void()> &&callable);
bool notify(QObject *receiver, QEvent *e) override;
void registerEnterFromEventLoop();
auto createEventNestingLevel() {
incrementEventNestingLevel();
return gsl::finally([=] { decrementEventNestingLevel(); });
}
void activateWindowDelayed(not_null<QWidget*> widget);
void pauseDelayedWindowActivations();
@ -65,6 +70,8 @@ private:
FnMut<void()> callable;
};
void incrementEventNestingLevel();
void decrementEventNestingLevel();
bool nativeEventFilter(
const QByteArray &eventType,
void *message,

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "core/main_queue_processor.h"
#include "application.h"
namespace Core {
namespace {
@ -38,15 +40,6 @@ void ProcessorEvent::process() {
_callable(_argument);
}
void ProcessMainQueue(void (*callable)(void*), void *argument) {
QMutexLocker lock(&ProcessorMutex);
if (ProcessorInstance) {
const auto event = new ProcessorEvent(callable, argument);
QCoreApplication::postEvent(ProcessorInstance, event);
}
}
void ProcessObservables() {
Global::RefHandleObservables().call();
}
@ -55,7 +48,20 @@ void ProcessObservables() {
MainQueueProcessor::MainQueueProcessor() {
acquire();
crl::init_main_queue(ProcessMainQueue);
crl::init_main_queue([](void (*callable)(void*), void *argument) {
QMutexLocker lock(&ProcessorMutex);
if (ProcessorInstance) {
const auto event = new ProcessorEvent(callable, argument);
QCoreApplication::postEvent(ProcessorInstance, event);
}
});
crl::wrap_main_queue([](void (*callable)(void*), void *argument) {
App().registerEnterFromEventLoop();
const auto wrap = App().createEventNestingLevel();
callable(argument);
});
base::InitObservables(ProcessObservables);
}

@ -1 +1 @@
Subproject commit 4291015efab76bda5886a56b5007f4531be17d46
Subproject commit 9b7c6b5d9f1b59d2160bf6e9c4e74510f955efe1