diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 2047f6f91b..8bc3a802be 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -242,8 +242,8 @@ public: ~NSViewComponentPeer() override { - CVDisplayLinkStop (displayLink); - dispatch_source_cancel (displaySource); + displayLink.reset(); + dispatchSource.reset(); scopedObservers.clear(); @@ -1784,47 +1784,90 @@ private: } //============================================================================== - void onDisplaySourceCallback() + void updateCVDisplayLinkScreen() { - setNeedsDisplayRectangles(); + const auto viewDisplayID = (CGDirectDisplayID) [[window.screen.deviceDescription objectForKey: @"NSScreenNumber"] unsignedIntegerValue]; + const auto result = CVDisplayLinkSetCurrentCGDisplay (displayLink->get(), viewDisplayID); + jassertquiet (result == kCVReturnSuccess); } - void onDisplayLinkCallback() + void createCVDisplayLink() { - dispatch_source_merge_data (displaySource, 1); - } + dispatchSource.reset (dispatch_source_create (DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue())); + dispatch_source_set_event_handler (dispatchSource.get(), ^(){ setNeedsDisplayRectangles(); }); - static CVReturn displayLinkCallback (CVDisplayLinkRef, const CVTimeStamp*, const CVTimeStamp*, - CVOptionFlags, CVOptionFlags*, void* context) - { - static_cast (context)->onDisplayLinkCallback(); - return kCVReturnSuccess; + if (@available (macOS 10.12, *)) + dispatch_activate (dispatchSource.get()); + else + dispatch_resume (dispatchSource.get()); + + displayLink.emplace (this); } - void updateCVDisplayLinkScreen() + struct DisplayLinkDestructor { - auto viewDisplayID = (CGDirectDisplayID) [[window.screen.deviceDescription objectForKey: @"NSScreenNumber"] unsignedIntegerValue]; - auto result = CVDisplayLinkSetCurrentCGDisplay (displayLink, viewDisplayID); - jassertquiet (result == kCVReturnSuccess); - } + void operator() (CVDisplayLinkRef ptr) const + { + if (ptr != nullptr) + CVDisplayLinkRelease (ptr); + } + }; - void createCVDisplayLink() + class ScopedDisplayLink { - displaySource = dispatch_source_create (DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); - dispatch_source_set_event_handler (displaySource, ^(){ onDisplaySourceCallback(); }); - dispatch_resume (displaySource); + public: + explicit ScopedDisplayLink (NSViewComponentPeer* owner) + { + const auto callback = [] (CVDisplayLinkRef, + const CVTimeStamp*, + const CVTimeStamp*, + CVOptionFlags, + CVOptionFlags*, + void* context) -> int + { + dispatch_source_merge_data (static_cast (context)->dispatchSource.get(), 1); + return kCVReturnSuccess; + }; - auto cvReturn = CVDisplayLinkCreateWithActiveCGDisplays (&displayLink); - jassertquiet (cvReturn == kCVReturnSuccess); + const auto callbackResult = CVDisplayLinkSetOutputCallback (link.get(), callback, owner); + jassertquiet (callbackResult == kCVReturnSuccess); - cvReturn = CVDisplayLinkSetOutputCallback (displayLink, &displayLinkCallback, this); - jassertquiet (cvReturn == kCVReturnSuccess); + const auto startResult = CVDisplayLinkStart (link.get()); + jassertquiet (startResult == kCVReturnSuccess); + } - CVDisplayLinkStart (displayLink); - } + ~ScopedDisplayLink() + { + CVDisplayLinkStop (link.get()); + } + + CVDisplayLinkRef get() const { return link.get(); } + + private: + std::unique_ptr, DisplayLinkDestructor> link + { + [] + { + CVDisplayLinkRef ptr = nullptr; + const auto result = CVDisplayLinkCreateWithActiveCGDisplays (&ptr); + jassertquiet (result == kCVReturnSuccess); + jassertquiet (ptr != nullptr); + return ptr; + }() + }; + }; + + struct DispatchSourceDestructor + { + void operator() (dispatch_source_t ptr) const + { + if (ptr != nullptr) + dispatch_source_cancel (ptr); + } + }; - CVDisplayLinkRef displayLink = nullptr; - dispatch_source_t displaySource = nullptr; + Optional displayLink; + std::unique_ptr, DispatchSourceDestructor> dispatchSource; int numFramesToSkipMetalRenderer = 0; std::unique_ptr> metalRenderer;