Add Ui::PostponeCall() on return to event loop.

This commit is contained in:
John Preston 2018-12-12 12:59:51 +04:00
parent a167a8587b
commit 89cf733d24
5 changed files with 95 additions and 2 deletions

View File

@ -102,6 +102,7 @@ Application::Application(
int &argc,
char **argv)
: QApplication(argc, argv)
, _mainThreadId(QThread::currentThreadId())
, _launcher(launcher)
, _updateChecker(Core::UpdaterDisabled()
? nullptr
@ -356,6 +357,12 @@ void Application::createMessenger() {
Expects(!App::quitting());
_messengerInstance = std::make_unique<Messenger>(_launcher);
// Ideally this should go to constructor.
// But we want to catch all native events and Messenger installs
// its own filter that can filter out some of them. So we install
// our filter after the Messenger constructor installs his.
installNativeEventFilter(this);
}
void Application::refreshGlobalProxy() {
@ -381,6 +388,53 @@ void Application::refreshGlobalProxy() {
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
}
void Application::postponeCall(FnMut<void()> &&callable) {
Expects(callable != nullptr);
Expects(_eventNestingLevel > _loopNestingLevel);
_postponedCalls.push_back({
_loopNestingLevel,
std::move(callable)
});
}
bool Application::notify(QObject *receiver, QEvent *e) {
if (QThread::currentThreadId() != _mainThreadId) {
return QApplication::notify(receiver, e);
}
++_eventNestingLevel;
const auto result = QApplication::notify(receiver, e);
if (_eventNestingLevel == _loopNestingLevel) {
_loopNestingLevel = _previousLoopNestingLevels.back();
_previousLoopNestingLevels.pop_back();
}
processPostponedCalls(--_eventNestingLevel);
return result;
}
void Application::processPostponedCalls(int level) {
while (!_postponedCalls.empty()) {
auto &last = _postponedCalls.back();
if (last.loopNestingLevel != level) {
break;
}
auto taken = std::move(last);
_postponedCalls.pop_back();
taken.callable();
}
}
bool Application::nativeEventFilter(
const QByteArray &eventType,
void *message,
long *result) {
if (_eventNestingLevel > _loopNestingLevel) {
_previousLoopNestingLevels.push_back(_loopNestingLevel);
_loopNestingLevel = _eventNestingLevel;
}
return false;
}
void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed);

View File

@ -15,7 +15,7 @@ class UpdateChecker;
bool InternalPassportLink(const QString &url);
bool StartUrlRequiresActivate(const QString &url);
class Application : public QApplication {
class Application : public QApplication, private QAbstractNativeEventFilter {
Q_OBJECT
public:
@ -26,6 +26,9 @@ public:
void createMessenger();
void refreshGlobalProxy();
void postponeCall(FnMut<void()> &&callable);
bool notify(QObject *receiver, QEvent *e) override;
~Application();
signals:
@ -50,6 +53,23 @@ private:
typedef QPair<QLocalSocket*, QByteArray> LocalClient;
typedef QList<LocalClient> LocalClients;
struct PostponedCall {
int loopNestingLevel = 0;
FnMut<void()> callable;
};
bool nativeEventFilter(
const QByteArray &eventType,
void *message,
long *result) override;
void processPostponedCalls(int level);
const Qt::HANDLE _mainThreadId = nullptr;
int _eventNestingLevel = 0;
int _loopNestingLevel = 0;
std::vector<int> _previousLoopNestingLevels;
std::vector<PostponedCall> _postponedCalls;
not_null<Core::Launcher*> _launcher;
std::unique_ptr<Messenger> _messengerInstance;

View File

@ -233,6 +233,11 @@ void ForceFullRepaint(not_null<QWidget*> widget) {
refresher->show();
}
void PostponeCall(FnMut<void()> &&callable) {
const auto app = static_cast<Application*>(qApp);
app->postponeCall(std::move(callable));
}
} // namespace Ui
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) {

View File

@ -59,6 +59,20 @@ QImage GrabWidgetToImage(
void ForceFullRepaint(not_null<QWidget*> widget);
void PostponeCall(FnMut<void()> &&callable);
template <
typename Guard,
typename Callable,
typename GuardTraits = crl::guard_traits<std::decay_t<Guard>>,
typename = std::enable_if_t<
sizeof(GuardTraits) != crl::details::dependent_zero<GuardTraits>>>
inline void PostponeCall(Guard &&object, Callable &&callable) {
return PostponeCall(crl::guard(
std::forward<Guard>(object),
std::forward<Callable>(callable)));
}
} // namespace Ui
enum class RectPart {

View File

@ -375,7 +375,7 @@ void LayerStackWidget::keyPressEvent(QKeyEvent *e) {
}
void LayerStackWidget::mousePressEvent(QMouseEvent *e) {
crl::on_main(this, [=] { backgroundClicked(); });
Ui::PostponeCall(this, [=] { backgroundClicked(); });
}
void LayerStackWidget::backgroundClicked() {