Browse Source

Added some workarounds in the OSX windowing code to help keep window resizing smooth when components are repainting at high speeds (only seems to be an issue since OSX 10.11)

tags/2021-05-28
jules 9 years ago
parent
commit
328652c3ad
3 changed files with 91 additions and 70 deletions
  1. +12
    -8
      modules/juce_events/native/juce_osx_MessageQueue.h
  2. +1
    -1
      modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h
  3. +78
    -61
      modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm

+ 12
- 8
modules/juce_events/native/juce_osx_MessageQueue.h View File

@@ -46,7 +46,7 @@ public:
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
}
~MessageQueue()
~MessageQueue() noexcept
{
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
CFRunLoopSourceInvalidate (runLoopSource);
@@ -56,15 +56,20 @@ public:
void post (MessageManager::MessageBase* const message)
{
messages.add (message);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
wakeUp();
}
private:
ReferenceCountedArray <MessageManager::MessageBase, CriticalSection> messages;
ReferenceCountedArray<MessageManager::MessageBase, CriticalSection> messages;
CFRunLoopRef runLoop;
CFRunLoopSourceRef runLoopSource;
void wakeUp() noexcept
{
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
bool deliverNextMessage()
{
const MessageManager::MessageBase::Ptr nextMessage (messages.removeAndReturn (0));
@@ -84,17 +89,16 @@ private:
return true;
}
void runLoopCallback()
void runLoopCallback() noexcept
{
for (int i = 4; --i >= 0;)
if (! deliverNextMessage())
return;
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
wakeUp();
}
static void runLoopSourceCallback (void* info)
static void runLoopSourceCallback (void* info) noexcept
{
static_cast<MessageQueue*> (info)->runLoopCallback();
}


+ 1
- 1
modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h View File

@@ -29,7 +29,7 @@
class CoreGraphicsContext : public LowLevelGraphicsContext
{
public:
CoreGraphicsContext (CGContextRef context, const float flipHeight, const float targetScale);
CoreGraphicsContext (CGContextRef context, float flipHeight, float targetScale);
~CoreGraphicsContext();
//==============================================================================


+ 78
- 61
modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -59,7 +59,8 @@ static NSRect flippedScreenRect (NSRect r) noexcept
}
//==============================================================================
class NSViewComponentPeer : public ComponentPeer
class NSViewComponentPeer : public ComponentPeer,
private AsyncUpdater
{
public:
NSViewComponentPeer (Component& comp, const int windowStyleFlags, NSView* viewToAttachTo)
@@ -773,6 +774,7 @@ public:
handleModifierKeysChange();
}
//==============================================================================
void drawRect (NSRect r)
{
if (r.size.width < 1.0f || r.size.height < 1.0f)
@@ -795,10 +797,7 @@ public:
if (usingCoreGraphics)
{
CoreGraphicsContext context (cg, (float) [view frame].size.height, displayScale);
insideDrawRect = true;
handlePaint (context);
insideDrawRect = false;
invokePaint (context);
}
else
#endif
@@ -829,9 +828,7 @@ public:
if (intScale != 1)
context->addTransform (AffineTransform::scale (displayScale));
insideDrawRect = true;
handlePaint (*context);
insideDrawRect = false;
invokePaint (*context);
}
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
@@ -843,6 +840,62 @@ public:
}
}
void handleAsyncUpdate() override
{
// When windows are being resized, artificially throttling high-frequency repaints helps
// to stop the event queue getting clogged, and keeps everything working smoothly
if (areAnyWindowsInLiveResize()
&& Time::getCurrentTime() < lastRepaintTime + RelativeTime::milliseconds (1000 / 30))
{
triggerAsyncUpdate();
return;
}
for (const Rectangle<float>* i = deferredRepaints.begin(), *e = deferredRepaints.end(); i != e; ++i)
[view setNeedsDisplayInRect: makeNSRect (*i)];
deferredRepaints.clear();
}
void repaint (const Rectangle<int>& area) override
{
Rectangle<float> r ((float) area.getX(), [view frame].size.height - (float) area.getBottom(),
(float) area.getWidth(), (float) area.getHeight());
if (insideDrawRect || areAnyWindowsInLiveResize())
{
deferredRepaints.add (r);
triggerAsyncUpdate();
}
else
{
[view setNeedsDisplayInRect: makeNSRect (r)];
}
}
void invokePaint (LowLevelGraphicsContext& context)
{
lastRepaintTime = Time::getCurrentTime();
insideDrawRect = true;
handlePaint (context);
insideDrawRect = false;
}
void performAnyPendingRepaintsNow() override
{
[view displayIfNeeded];
}
static bool areAnyWindowsInLiveResize() noexcept
{
for (NSWindow* w in [NSApp windows])
if ([w inLiveResize])
return true;
return false;
}
//==============================================================================
bool sendModalInputAttemptIfBlocked()
{
if (Component* modal = Component::getCurrentlyModalComponent())
@@ -1231,43 +1284,6 @@ public:
void textInputRequired (Point<int>, TextInputTarget&) override {}
//==============================================================================
void repaint (const Rectangle<int>& area) override
{
if (insideDrawRect)
{
class AsyncRepaintMessage : public CallbackMessage
{
public:
AsyncRepaintMessage (NSViewComponentPeer* const p, const Rectangle<int>& r)
: peer (p), rect (r)
{}
void messageCallback() override
{
if (ComponentPeer::isValidPeer (peer))
peer->repaint (rect);
}
private:
NSViewComponentPeer* const peer;
const Rectangle<int> rect;
};
(new AsyncRepaintMessage (this, area))->post();
}
else
{
[view setNeedsDisplayInRect: NSMakeRect ((CGFloat) area.getX(), [view frame].size.height - (CGFloat) area.getBottom(),
(CGFloat) area.getWidth(), (CGFloat) area.getHeight())];
}
}
void performAnyPendingRepaintsNow() override
{
[view displayIfNeeded];
}
//==============================================================================
NSWindow* window;
NSView* view;
@@ -1276,6 +1292,9 @@ public:
String stringBeingComposed;
NSNotificationCenter* notificationCenter;
RectangleList<float> deferredRepaints;
Time lastRepaintTime;
static ModifierKeys currentModifiers;
static ComponentPeer* currentlyFocusedPeer;
static Array<int> keysCurrentlyDown;
@@ -1375,24 +1394,22 @@ private:
for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
{
ComponentPeer* const peer = ComponentPeer::getPeer (i);
NSView* const compView = (NSView*) peer->getNativeHandle();
if ([compView window] == w)
if (NSViewComponentPeer* peer = dynamic_cast<NSViewComponentPeer*> (ComponentPeer::getPeer (i)))
{
if (isKey)
if ([peer->view window] == w)
{
if (compView == [w firstResponder])
return false;
}
else
{
NSViewComponentPeer* nsViewPeer = dynamic_cast<NSViewComponentPeer*> (peer);
if ((nsViewPeer == nullptr || ! nsViewPeer->isSharedWindow)
? NSPointInRect ([e locationInWindow], NSMakeRect (0, 0, [w frame].size.width, [w frame].size.height))
: NSPointInRect ([compView convertPoint: [e locationInWindow] fromView: nil], [compView bounds]))
return false;
if (isKey)
{
if (peer->view == [w firstResponder])
return false;
}
else
{
if (peer->isSharedWindow
? NSPointInRect ([peer->view convertPoint: [e locationInWindow] fromView: nil], [peer->view bounds])
: NSPointInRect ([e locationInWindow], NSMakeRect (0, 0, [w frame].size.width, [w frame].size.height)))
return false;
}
}
}
}


Loading…
Cancel
Save