Skip to content

Commit

Permalink
Merge remote-tracking branch 'cfillion/wait-on-macos' into v2.13.2
Browse files Browse the repository at this point in the history
  • Loading branch information
cfillion committed Jan 11, 2023
2 parents 8b76551 + 8af6ffb commit b2a2c32
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 41 deletions.
77 changes: 39 additions & 38 deletions Misc/Macros.cpp
Expand Up @@ -30,47 +30,47 @@
#include "stdafx.h"
#include "Macros.h"

#ifdef _WIN32 // Sorry OSX users, win32 only.
// WaitUntil is not implemented for swell-generic (sws_util_generic.cpp)
#if defined(_WIN32) || defined(__APPLE__)
# define HAS_WAITACTION

void WaitAction(COMMAND_T* t)
{
int iPlayState = GetPlayState();
if (iPlayState && !(iPlayState & 2)) // playing/recording, not paused
{
int iMeasure;
double dStart = GetPlayPosition();
double dBeat = TimeMap2_timeToBeats(NULL, dStart, &iMeasure, NULL, NULL, NULL);
double dStop;
switch (t->user)
{
case 0: // Bar
iMeasure++;
dBeat = 0.0;
dStop = TimeMap2_beatsToTime(NULL, dBeat, &iMeasure);
break;
case 1:
dBeat = (double)((int)dBeat + 1);
dStop = TimeMap2_beatsToTime(NULL, dBeat, &iMeasure);
break;
case 2:
double t1, t2;
GetSet_LoopTimeRange(false, true, &t1, &t2, false);
if (t1 == t2)
return;
dStop = t2;
break;
}
const int iPlayState = GetPlayState();
if (!iPlayState || (iPlayState & 2)) // playing/recording, not paused
return;

// Check for cursor going past stop, user stopping, and looping around
while(GetPlayPosition() < dStop && GetPlayState() && GetPlayPosition() >= dStart)
{
// Keep the UI updating
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
DispatchMessage(&msg);
Sleep(1);
}
struct WaitData { double dStart, dStop; };
WaitData wd;
wd.dStart = GetPlayPosition();
int iMeasure;
double dBeat = TimeMap2_timeToBeats(NULL, wd.dStart, &iMeasure, NULL, NULL, NULL);
switch (t->user)
{
case 0: // Bar
iMeasure++;
dBeat = 0.0;
wd.dStop = TimeMap2_beatsToTime(NULL, dBeat, &iMeasure);
break;
case 1:
dBeat = (double)((int)dBeat + 1);
wd.dStop = TimeMap2_beatsToTime(NULL, dBeat, &iMeasure);
break;
case 2:
double t1, t2;
GetSet_LoopTimeRange(false, true, &t1, &t2, false);
if (t1 == t2)
return;
wd.dStop = t2;
break;
}

// Check for cursor going past stop, user stopping, and looping around
WaitUntil([](void *data) {
WaitData *wd = static_cast<WaitData *>(data);
const double pos = GetPlayPosition();
return !GetPlayState() || pos >= wd->dStop || pos < wd->dStart;
}, &wd);
}

//!WANT_LOCALIZE_1ST_STRING_BEGIN:sws_actions
Expand All @@ -83,12 +83,13 @@ static COMMAND_T g_commandTable[] =
{ {}, LAST_COMMAND, }, // Denote end of table
};
//!WANT_LOCALIZE_1ST_STRING_END
#endif

int MacrosInit()
{
#ifdef HAS_WAITACTION
SWSRegisterCommands(g_commandTable);
#endif

return 1;
}

#endif // #ifdef _WIN32
2 changes: 0 additions & 2 deletions Misc/Misc.cpp
Expand Up @@ -71,10 +71,8 @@ int MiscInit()
return 0;
if (!ItemSelInit())
return 0;
#ifdef _WIN32
if (!MacrosInit())
return 0;
#endif
if (!ProjPrefsInit())
return 0;
if (!RecordCheckInit())
Expand Down
12 changes: 12 additions & 0 deletions sws_util.cpp
Expand Up @@ -723,3 +723,15 @@ const char* SWS_GetSourceFileName(PCM_source* src)
src = src->GetSource();
return src ? src->GetFileName() : nullptr;
}

#ifdef _WIN32
void WaitUntil(bool(*predicate)(void *), void *data)
{
while (!predicate(data)) {
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
DispatchMessage(&msg);
Sleep(1);
}
}
#endif
2 changes: 1 addition & 1 deletion sws_util.h
Expand Up @@ -264,6 +264,7 @@ void SWS_GetSelectedMediaItems(WDL_TypedBuf<MediaItem*>* buf);
void SWS_GetSelectedMediaItemsOnTrack(WDL_TypedBuf<MediaItem*>* buf, MediaTrack* tr);
int SWS_GetModifiers();
bool SWS_IsWindow(HWND hwnd);
void WaitUntil(bool(*)(void *), void *); // cannot use std::function on pre-c++11 macOS

// Localization, sws_util.cpp
#define _SWS_LOCALIZATION
Expand All @@ -278,4 +279,3 @@ TrackEnvelope* SWS_GetTrackEnvelopeByName(MediaTrack* track, const char* envname
bool RegisterExportedFuncs(reaper_plugin_info_t* _rec);
void UnregisterExportedFuncs();
bool RegisterExportedAPI(reaper_plugin_info_t* _rec);

36 changes: 36 additions & 0 deletions sws_util.mm
Expand Up @@ -237,3 +237,39 @@ void SetMenuItemSwatch(HMENU hMenu, UINT pos, int iSize, COLORREF color)
NSRectFill(NSMakeRect(0, 0, size.width, size.height));
[item.image unlockFocus];
}

static bool g_miscTimerRunning;
void TestMiscTimerRunning()
{
g_miscTimerRunning = true;
plugin_register("-timer", reinterpret_cast<void *>(&TestMiscTimerRunning));
}

void WaitUntil(bool(*predicate)(void *), void *data)
{
g_miscTimerRunning = false;
plugin_register("timer", reinterpret_cast<void *>(&TestMiscTimerRunning));

bool firstRun = true;
while (!predicate(data)) {
// Waiting 30 ms instead of 1 ms (like on Windows) to match the normal
// frequency of REAPER's misc timer
constexpr int DEFER_TIMER_SPEED = 30,
MISC_TIMER = 0x29A;

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:DEFER_TIMER_SPEED / 1000.f]];

// REAPER's misc timer (based on NSTimer), responsible for many many things
// from UI updates to updating GetPlayPosition(), won't be re-entered in the
// event loop iterations above while if we're blocking it's handler.
//
// Wait until we're 100% sure the misc timer is suspended
// (by waiting twice its normal fire rate) before manually triggering it.
if (firstRun)
firstRun = false;
else if (!g_miscTimerRunning) {
plugin_register("-timer", reinterpret_cast<void *>(&TestMiscTimerRunning));
PostMessage(GetMainHwnd(), WM_TIMER, MISC_TIMER, 0);
}
}
}
5 changes: 5 additions & 0 deletions sws_util_generic.cpp
Expand Up @@ -67,3 +67,8 @@ HCURSOR SWS_Cursor::makeFromData()
void mouse_event(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo)
{
}

// not implemented, would be used by WaitAction in Macros.cpp
// void waitUntil(bool(*)(void *), void *)
// {
// }

0 comments on commit b2a2c32

Please sign in to comment.