From b8f71efc04c10ca3fffda676aaa4c8556cd4a484 Mon Sep 17 00:00:00 2001 From: Graham Dawes Date: Wed, 23 Jan 2019 11:55:56 +0000 Subject: [PATCH 1/5] Implement filtering in wxEventLoop::DoYieldFor under wxQT --- src/qt/evtloop.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/qt/evtloop.cpp b/src/qt/evtloop.cpp index 132d6533c2..d15ec1ed10 100644 --- a/src/qt/evtloop.cpp +++ b/src/qt/evtloop.cpp @@ -131,10 +131,17 @@ void wxQtEventLoopBase::WakeUp() void wxQtEventLoopBase::DoYieldFor(long eventsToProcess) { - while (wxTheApp && wxTheApp->Pending()) - // TODO: implement event filtering using the eventsToProcess mask - wxTheApp->Dispatch(); + QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents; + + if ( !(eventsToProcess & wxEVT_CATEGORY_USER_INPUT) ) + flags |= QEventLoop::ExcludeUserInputEvents; + + if ( !(eventsToProcess & wxEVT_CATEGORY_SOCKET) ) + flags |= QEventLoop::ExcludeSocketNotifiers; + + m_qtEventLoop->processEvents(flags); + wxEventLoopBase::DoYieldFor(eventsToProcess); } From 0c28952ff63bd106b56e9f005171ea46aff46011 Mon Sep 17 00:00:00 2001 From: Graham Dawes Date: Wed, 23 Jan 2019 12:04:42 +0000 Subject: [PATCH 2/5] Make ScheduleIdleCheck take into account whether the loop is exiting --- src/qt/evtloop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/evtloop.cpp b/src/qt/evtloop.cpp index d15ec1ed10..4b7339e012 100644 --- a/src/qt/evtloop.cpp +++ b/src/qt/evtloop.cpp @@ -141,13 +141,13 @@ void wxQtEventLoopBase::DoYieldFor(long eventsToProcess) flags |= QEventLoop::ExcludeSocketNotifiers; m_qtEventLoop->processEvents(flags); - + wxEventLoopBase::DoYieldFor(eventsToProcess); } void wxQtEventLoopBase::ScheduleIdleCheck() { - if ( IsInsideRun() ) + if ( IsInsideRun() && !m_shouldExit ) m_qtIdleTimer->start(0); } From 6aecaa88452ee132b388088b301c1bc2f2feb06f Mon Sep 17 00:00:00 2001 From: Graham Dawes Date: Wed, 23 Jan 2019 13:55:20 +0000 Subject: [PATCH 3/5] Share a single idle timer for all event loops in wxQT --- src/qt/evtloop.cpp | 79 ++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/src/qt/evtloop.cpp b/src/qt/evtloop.cpp index 4b7339e012..71ae83707a 100644 --- a/src/qt/evtloop.cpp +++ b/src/qt/evtloop.cpp @@ -21,33 +21,48 @@ #include -class wxQtIdleTimer : public QTimer +class wxQtIdleTimer : public QTimer, public wxRefCounter { public: - wxQtIdleTimer( wxQtEventLoopBase *eventLoop ); + wxQtIdleTimer(); + ~wxQtIdleTimer(); virtual bool eventFilter( QObject * watched, QEvent * event ); private: void idle(); - -private: - wxQtEventLoopBase *m_eventLoop; + void ScheduleIdleCheck(); }; -wxQtIdleTimer::wxQtIdleTimer( wxQtEventLoopBase *eventLoop ) +wxQtIdleTimer::wxQtIdleTimer() { - m_eventLoop = eventLoop; + // We need a QCoreApplication for event loops, create it here if it doesn't + // already exist as we can't modify wxAppConsole + if ( !QCoreApplication::instance() ) + { + new QApplication(wxAppConsole::GetInstance()->argc, wxAppConsole::GetInstance()->argv); + } - connect( this, &QTimer::timeout, this, &wxQtIdleTimer::idle ); - setSingleShot( true ); + + // Pass all events to the idle timer, so it can be restarted each time + // an event is received + qApp->installEventFilter(this); + + connect(this, &QTimer::timeout, this, &wxQtIdleTimer::idle); + setSingleShot(true); +} + + +wxQtIdleTimer::~wxQtIdleTimer() +{ + qApp->removeEventFilter(this); } bool wxQtIdleTimer::eventFilter( QObject *WXUNUSED( watched ), QEvent *WXUNUSED( event ) ) { // Called for each Qt event, start with timeout 0 (run as soon as idle) if ( !isActive() ) - m_eventLoop->ScheduleIdleCheck(); + ScheduleIdleCheck(); return false; // Continue handling the event } @@ -59,35 +74,45 @@ void wxQtIdleTimer::idle() wxTheApp->ProcessPendingEvents(); // Send idle event - if ( m_eventLoop->ProcessIdle() ) - m_eventLoop->ScheduleIdleCheck(); + if (wxTheApp->ProcessIdle()) + ScheduleIdleCheck(); +} + + +namespace +{ + wxQtIdleTimer *gs_idleTimer = NULL; +} + +void wxQtIdleTimer::ScheduleIdleCheck() +{ + wxQtEventLoopBase *eventLoop = static_cast(wxEventLoop::GetActive()); + if ( eventLoop ) + eventLoop->ScheduleIdleCheck(); } wxQtEventLoopBase::wxQtEventLoopBase() { - // We need a QCoreApplication for event loops, create it here if it doesn't - // already exist as we can't modify wxAppConsole - if ( !QCoreApplication::instance() ) - { - new QApplication( wxAppConsole::GetInstance()->argc, wxAppConsole::GetInstance()->argv ); - } - // Create an idle timer to run each time there are no events (timeout = 0) - m_qtIdleTimer = new wxQtIdleTimer( this ); - - // Pass all events to the idle timer, so it can be restarted each time - // an event is received - qApp->installEventFilter( m_qtIdleTimer ); - + if ( !gs_idleTimer ) + { + gs_idleTimer = new wxQtIdleTimer(); + } + else + { + gs_idleTimer->IncRef(); + } + m_qtIdleTimer = gs_idleTimer; m_qtEventLoop = new QEventLoop; } wxQtEventLoopBase::~wxQtEventLoopBase() { - qApp->removeEventFilter(m_qtIdleTimer); + if ( gs_idleTimer->GetRefCount() <= 1 ) + gs_idleTimer = NULL; + delete m_qtEventLoop; - delete m_qtIdleTimer; } void wxQtEventLoopBase::ScheduleExit(int rc) From 9cd566789df0ea3c4f8b89652cddb1d0de433686 Mon Sep 17 00:00:00 2001 From: Graham Dawes Date: Thu, 24 Jan 2019 08:08:12 +0000 Subject: [PATCH 4/5] Added file missing from previous commit --- include/wx/qt/evtloop.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/wx/qt/evtloop.h b/include/wx/qt/evtloop.h index dbdbd6a5a0..5419916281 100644 --- a/include/wx/qt/evtloop.h +++ b/include/wx/qt/evtloop.h @@ -8,7 +8,7 @@ #ifndef _WX_QT_EVTLOOP_H_ #define _WX_QT_EVTLOOP_H_ -class QTimer; +class wxQtIdleTimer; class QEventLoop; class WXDLLIMPEXP_CORE wxQtEventLoopBase : public wxEventLoopBase @@ -30,12 +30,11 @@ public: #if wxUSE_EVENTLOOP_SOURCE virtual wxEventLoopSource *AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags); #endif // wxUSE_EVENTLOOP_SOURCE -protected: private: QEventLoop *m_qtEventLoop; - QTimer *m_qtIdleTimer; - + wxObjectDataPtr m_qtIdleTimer; + wxDECLARE_NO_COPY_CLASS(wxQtEventLoopBase); }; From e40323d3120c9297590641e82fa4616e272962a3 Mon Sep 17 00:00:00 2001 From: Graham Dawes Date: Fri, 25 Jan 2019 16:44:23 +0000 Subject: [PATCH 5/5] Simplify shared timer reference counting in wxEventLoop for wxQT --- src/qt/evtloop.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/qt/evtloop.cpp b/src/qt/evtloop.cpp index 71ae83707a..1341ca115c 100644 --- a/src/qt/evtloop.cpp +++ b/src/qt/evtloop.cpp @@ -81,7 +81,7 @@ void wxQtIdleTimer::idle() namespace { - wxQtIdleTimer *gs_idleTimer = NULL; + wxObjectDataPtr gs_idleTimer; } void wxQtIdleTimer::ScheduleIdleCheck() @@ -95,13 +95,7 @@ wxQtEventLoopBase::wxQtEventLoopBase() { // Create an idle timer to run each time there are no events (timeout = 0) if ( !gs_idleTimer ) - { - gs_idleTimer = new wxQtIdleTimer(); - } - else - { - gs_idleTimer->IncRef(); - } + gs_idleTimer.reset(new wxQtIdleTimer()); m_qtIdleTimer = gs_idleTimer; m_qtEventLoop = new QEventLoop; @@ -109,8 +103,9 @@ wxQtEventLoopBase::wxQtEventLoopBase() wxQtEventLoopBase::~wxQtEventLoopBase() { - if ( gs_idleTimer->GetRefCount() <= 1 ) - gs_idleTimer = NULL; + //Clear the shared timer if this is the only external reference to it + if ( gs_idleTimer->GetRefCount() <= 2 ) + gs_idleTimer.reset(NULL); delete m_qtEventLoop; }