I just noticed this problem with JUCE 8.0.3 (MacOS, BigSur, Intel).
I use a CodeEditorComponent as a sort of debugging message window.
In JUCE 7, you can literally print a message every 1 ms and it prints them all extremely smoothly, one by one, scrolling without any jerking or halting.
In JUCE 8, it jerks and halts and falls behind.
Here is a test app demonstrating the issue:
CodeEditorTest.zip (14.8 KB)
It uses a HighResolutionTimer to create a String with a timestamp every 1 ms, and the Strings are then concatenated into blocks of text that are updated to the CodeEditorComponent using AsyncUpdater.
Here is a movie showing a side-by-side comparison of JUCE 7.0.12 (left) and JUCE 8.0.3 (right).
As you can see, JUCE 7 is scrolling smoothly and printing every single message one by one. JUCE 8 is jerking and halting and printing blocks.
The JUCE 8 version also gets “behind” and can’t keep up - if you let it run for awhile, then turn it off (by clicking the On/Off button), it keeps going for awhile. The JUCE 7 version stops instantly because it is keeping up with real time.
So I don’t know if this is a problem with the new Glyph handling code of JUCE 8, or some problem with the AsyncUpdater, or the CodeEditorComponent, or something else.
(Is there anything in JUCE 8 that is limiting the frequency with which AsyncUpdater issues the handleAsyncUpdate callback?)
Here is the relevant code (from the test app) that formats and prints the text - in case there’s something wrong with it. But this has been working smoothly for years, and is based on discussions and info on this forum.
void MainComponent::hiResTimerCallback()
{
double hiResTime = juce::Time::getMillisecondCounterHiRes();
long inSeconds = (long) (hiResTime * .001);
auto hours3 = ((int) (inSeconds / 3600)) % 24;
auto minutes3 = ((int) (inSeconds / 60)) % 60;
auto seconds3 = ((int) inSeconds) % 60;
auto millis3 = ((int) (hiResTime) % 1000);
auto micros3 = ((long long) (hiResTime * 1000) % 1000); // can be out of range for int
juce::String timeStamp;
timeStamp = juce::String::formatted("%02d:%02d:%02d.%03d %03lld",
hours3, minutes3, seconds3, millis3, micros3 );
addMessage(timeStamp + " - " + juce::String(count++) + " Here is a big long message with a whole lotta text to be printed ");
}
void MainComponent::addMessage(juce::String messageText)
{
// add the message string to the list of messages that need to be posted asynchronously
// and trigger a call to AsyncUpdate
{
const juce::ScopedLock sl (messageListLock);
messageList.add(messageText);
triggerAsyncUpdate(); // all examples have this inside the lock, I don't know why
}
}
void MainComponent::handleAsyncUpdate()
{
// here we create an empty string array
// lock the messageList and swap it with the empty one
// therefore we empty the main list and now have a local copy of it
// the lock prevents it from being altered while we are swapping it
juce::StringArray messages;
{
const juce::ScopedLock sl (messageListLock);
messages.swapWith (messageList);
}
// assemble a chunk of text containing strings followed by line returns
juce::String messageText;
for (auto& string : messages)
messageText << string << "\n";
// add the text or text chunk to the end of the messageDisplay
messageDisplay->moveCaretToEnd(false);
messageDisplay->insertTextAtCaret (messageText);
}
