diff --git a/add_ons/qt/promise_qt.hpp b/add_ons/qt/promise_qt.hpp index 27e1c03..0c1c2bd 100644 --- a/add_ons/qt/promise_qt.hpp +++ b/add_ons/qt/promise_qt.hpp @@ -45,6 +45,7 @@ #include #include #include +#include namespace promise { @@ -75,28 +76,31 @@ class PromiseEventFilter : public QObject { protected: bool eventFilter(QObject *object, QEvent *event) { std::pair key = { object, event->type() }; - Listeners::iterator itr = listeners_.find(key); - if (itr != listeners_.end()) { - return itr->second(object, event); + + // may not safe if one handler is removed by other + std::list itrs; + for(Listeners::iterator itr = listeners_.lower_bound(key); + itr != listeners_.end() && key == itr->first; ++itr) { + itrs.push_back(itr); + } + for(Listeners::iterator itr: itrs) { + itr->second(object, event); } if (event->type() == QEvent::Destroy) { - return removeObjectFilters(object); + removeObjectFilters(object); } - return false; + return QObject::eventFilter(object, event); } bool removeObjectFilters(QObject *object) { std::pair key = { object, QEvent::None }; - std::list deletes; - - + // checked one by one for safety (others may be removed) while(true) { Listeners::iterator itr = listeners_.lower_bound(key); if(itr != listeners_.end() && itr->first.first == object) { - // one by one for safety itr->second(object, nullptr); } else { @@ -112,20 +116,34 @@ class PromiseEventFilter : public QObject { // Wait event will wait the event for only once inline Defer waitEvent(QObject *object, - QEvent::Type eventType) { + QEvent::Type eventType, + bool callSysHandler = false) { Defer promise = newPromise(); + std::shared_ptr disableFilter = std::make_shared(false); auto listener = PromiseEventFilter::getSingleInstance().addEventListener( - object, eventType, [promise](QObject *object, QEvent *event) { + object, eventType, [promise, callSysHandler, disableFilter](QObject *object, QEvent *event) { (void)object; - if (event == nullptr) + if (event == nullptr) { promise->reject(); + return false; + } + // The next then function will be call immediately + // Be care that do not use event in the next event loop + else if (*disableFilter) { + return false; + } + else if (callSysHandler) { + *disableFilter = true; + QApplication::sendEvent(object, event); + *disableFilter = false; + promise->resolve(event); + return true; + } else { - // The next then function will be call immediately - // Be care that do not use event in the next event loop promise->resolve(event); + return false; } - return false; } ); diff --git a/promise.hpp b/promise.hpp index 766c6f2..ea55f08 100644 --- a/promise.hpp +++ b/promise.hpp @@ -303,6 +303,10 @@ class pm_shared_ptr { return object_; } + inline T &operator*() const { + return *object_; + } + inline T *obtain_rawptr() { pm_allocator::add_ref(object_); return object_; @@ -1331,20 +1335,24 @@ inline Defer newPromise(FUNC func) { * if the returned Defer object was obtained by other and not released. */ template -inline Defer doWhile_unsafe(FUNC func) { - return newPromise(func).then([func]() { - return doWhile_unsafe(func); +inline Defer doWhile_unsafe(FUNC func, pm_shared_ptr current) { + *current = newPromise(func).then([current, func]() { + return doWhile_unsafe(func, current); }); + return *current; } /* While loop func call resolved */ template inline Defer doWhile(FUNC func) { - return newPromise([func](Defer d) { - doWhile_unsafe(func).then(d); - }).fail([](Defer &self, Promise *caller) -> BypassAndResolve { + pm_shared_ptr currnet = pm_shared_ptr(pm_new()); + + return newPromise([func, currnet](Defer d) { + doWhile_unsafe(func, currnet).then(d); + }).fail([currnet](Defer &self, Promise *caller) -> BypassAndResolve { (void)self; (void)caller; + currnet->doBreak(); return BypassAndResolve(); }); } @@ -1450,6 +1458,20 @@ inline Defer raceAndReject(PROMISE_LIST ...promise_list) { return raceAndReject({ promise_list ... }); } +inline Defer raceAndResolve(const std::initializer_list &promise_list) { + std::vector copy_list = promise_list; + return race(promise_list).finally([copy_list] { + for (auto defer : copy_list) { + defer.resolve(); + } + }); +} + +template +inline Defer raceAndResolve(PROMISE_LIST ...promise_list) { + return raceAndReject({ promise_list ... }); +} + #ifndef PM_EMBED inline void handleUncaughtException(const FnOnUncaughtException &onUncaughtException) {