1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-04-29 23:29:41 +02:00

Define CallAfter and Yield in BasicUI...

...so direct uses of wx/app.h may later be removed.  That header is one of the
files that is in wxBase, but is not acceptable in "toolkit neutral" code,
which should not directly use any version of an event loop.

Original commit: 50e8139716388f55b11abecb1fc46cbfcd38e247

Signed-off-by: Panagiotis Vasilopoulos <hello@alwayslivid.com>
This commit is contained in:
Paul Licameli 2021-02-07 22:06:20 -05:00 committed by Panagiotis Vasilopoulos
parent 2d0394796e
commit e5cffb7620
No known key found for this signature in database
GPG Key ID: 9E541BDE43B99F44
4 changed files with 78 additions and 2 deletions

View File

@ -9,6 +9,9 @@ Paul Licameli
**********************************************************************/
#include "BasicUI.h"
#include <mutex>
#include <vector>
namespace BasicUI {
Services::~Services() = default;
@ -22,4 +25,40 @@ Services *Install(Services *pInstance)
theInstance = pInstance;
return result;
}
static std::recursive_mutex sActionsMutex;
static std::vector<Action> sActions;
void CallAfter(Action action)
{
if (auto p = Get())
p->DoCallAfter(action);
else {
// No services yet -- but don't lose the action. Put it in a queue
auto guard = std::lock_guard{ sActionsMutex };
sActions.emplace_back(std::move(action));
}
}
void Yield()
{
do {
// Dispatch anything in the queue, added while there were no Services
{
auto guard = std::lock_guard{ sActionsMutex };
std::vector<Action> actions;
actions.swap(sActions);
for (auto &action : actions)
action();
}
// Dispatch according to Services, if present
if (auto p = Get())
p->DoYield();
}
// Re-test for more actions that might have been enqueued by actions just
// dispatched
while ( !sActions.empty() );
}
}

View File

@ -8,14 +8,18 @@ Audacity: A Digital Audio Editor
Paul Licameli
**********************************************************************/
#ifndef __AUDACITY_BASIC_UI__
#define __AUDACITY_BASIC_UI__
#ifndef __TENACITY_BASIC_UI__
#define __TENACITY_BASIC_UI__
#include <functional>
namespace BasicUI {
//! @name Types used in the Services interface
//! @{
using Action = std::function<void()>;
//! @}
//! Abstract class defines a few user interface services, not mentioning particular toolkits
@ -25,6 +29,8 @@ namespace BasicUI {
class BASIC_UI_API Services {
public:
virtual ~Services();
virtual void DoCallAfter(const Action &action) = 0;
virtual void DoYield() = 0;
};
//! Fetch the global instance, or nullptr if none is yet installed
@ -40,6 +46,21 @@ BASIC_UI_API Services *Install(Services *pInstance);
*/
//! @{
//! Schedule an action to be done later, and in the main thread
/*! This function may be called in other threads than the main. If no Services
are yet installed, the action is not lost, but may be dispatched by Yield().
The action may itself invoke CallAfter to enqueue other actions.
*/
void CallAfter(Action action);
//! Dispatch waiting events, including actions enqueued by CallAfter
/*! This function must be called by the main thread. Actions enqueued by
CallAfter before Services were installed will be dispatched in the sequence
they were enqueued, unless an exception thrown by one of them stops the
dispatching.
*/
void Yield();
//! @}
}

View File

@ -8,5 +8,18 @@ Paul Licameli
**********************************************************************/
#include "wxWidgetsBasicUI.h"
#include <wx/app.h>
using namespace BasicUI;
wxWidgetsBasicUI::~wxWidgetsBasicUI() = default;
void wxWidgetsBasicUI::DoCallAfter(const Action &action)
{
wxTheApp->CallAfter(action);
}
void wxWidgetsBasicUI::DoYield()
{
wxTheApp->Yield();
}

View File

@ -18,6 +18,9 @@ Paul Licameli
class wxWidgetsBasicUI final : public BasicUI::Services {
public:
~wxWidgetsBasicUI() override;
void DoCallAfter(const BasicUI::Action &action) override;
void DoYield() override;
};
#endif