This change allows mouse events (including enter and exit events) to reach unfocused views on macOS. This matches the behaviour of unfocused windows on Linux and Windows, where components paint in their "hovered" states even when the application window is in the background. As a byproduct of using tracking areas on macOS, we can remove the fake mouse move generator.v6.1.6
| @@ -31,7 +31,6 @@ | |||||
| #include "../utility/juce_IncludeSystemHeaders.h" | #include "../utility/juce_IncludeSystemHeaders.h" | ||||
| #include "../utility/juce_IncludeModuleHeaders.h" | #include "../utility/juce_IncludeModuleHeaders.h" | ||||
| #include "../utility/juce_WindowsHooks.h" | #include "../utility/juce_WindowsHooks.h" | ||||
| #include "../utility/juce_FakeMouseMoveGenerator.h" | |||||
| #include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp> | #include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp> | ||||
| @@ -592,8 +591,6 @@ namespace AAXClasses | |||||
| setBounds (lastValidSize); | setBounds (lastValidSize); | ||||
| pluginEditor->addMouseListener (this, true); | pluginEditor->addMouseListener (this, true); | ||||
| } | } | ||||
| ignoreUnused (fakeMouseGenerator); | |||||
| } | } | ||||
| ~ContentWrapperComponent() override | ~ContentWrapperComponent() override | ||||
| @@ -673,7 +670,6 @@ namespace AAXClasses | |||||
| #if JUCE_WINDOWS | #if JUCE_WINDOWS | ||||
| WindowsHooks hooks; | WindowsHooks hooks; | ||||
| #endif | #endif | ||||
| FakeMouseMoveGenerator fakeMouseGenerator; | |||||
| juce::Rectangle<int> lastValidSize; | juce::Rectangle<int> lastValidSize; | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent) | ||||
| @@ -81,7 +81,6 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||||
| #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 | #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 | ||||
| #include "../utility/juce_IncludeModuleHeaders.h" | #include "../utility/juce_IncludeModuleHeaders.h" | ||||
| #include "../utility/juce_FakeMouseMoveGenerator.h" | |||||
| #include "../utility/juce_CarbonVisibility.h" | #include "../utility/juce_CarbonVisibility.h" | ||||
| #include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h> | #include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h> | ||||
| @@ -1482,7 +1481,6 @@ public: | |||||
| setWantsKeyboardFocus (true); | setWantsKeyboardFocus (true); | ||||
| #endif | #endif | ||||
| ignoreUnused (fakeMouseGenerator); | |||||
| setBounds (getSizeToContainChild()); | setBounds (getSizeToContainChild()); | ||||
| lastBounds = getBounds(); | lastBounds = getBounds(); | ||||
| @@ -1594,7 +1592,6 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| FakeMouseMoveGenerator fakeMouseGenerator; | |||||
| Rectangle<int> lastBounds; | Rectangle<int> lastBounds; | ||||
| JUCE_DECLARE_NON_COPYABLE (EditorCompHolder) | JUCE_DECLARE_NON_COPYABLE (EditorCompHolder) | ||||
| @@ -2432,7 +2429,6 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| AudioProcessor* juceFilter; | AudioProcessor* juceFilter; | ||||
| std::unique_ptr<Component> windowComp; | std::unique_ptr<Component> windowComp; | ||||
| FakeMouseMoveGenerator fakeMouseGenerator; | |||||
| void deleteUI() | void deleteUI() | ||||
| { | { | ||||
| @@ -28,7 +28,6 @@ | |||||
| #include "../utility/juce_IncludeSystemHeaders.h" | #include "../utility/juce_IncludeSystemHeaders.h" | ||||
| #include "../utility/juce_IncludeModuleHeaders.h" | #include "../utility/juce_IncludeModuleHeaders.h" | ||||
| #include "../utility/juce_FakeMouseMoveGenerator.h" | |||||
| #include "../utility/juce_WindowsHooks.h" | #include "../utility/juce_WindowsHooks.h" | ||||
| #include <juce_audio_devices/juce_audio_devices.h> | #include <juce_audio_devices/juce_audio_devices.h> | ||||
| @@ -103,7 +103,6 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE | |||||
| using namespace juce; | using namespace juce; | ||||
| #include "../utility/juce_FakeMouseMoveGenerator.h" | |||||
| #include "../utility/juce_WindowsHooks.h" | #include "../utility/juce_WindowsHooks.h" | ||||
| #include "../utility/juce_LinuxMessageThread.h" | #include "../utility/juce_LinuxMessageThread.h" | ||||
| @@ -984,7 +983,6 @@ public: | |||||
| #endif | #endif | ||||
| setOpaque (true); | setOpaque (true); | ||||
| ignoreUnused (fakeMouseGenerator); | |||||
| } | } | ||||
| ~EditorCompWrapper() override | ~EditorCompWrapper() override | ||||
| @@ -1291,7 +1289,6 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| JuceVSTWrapper& wrapper; | JuceVSTWrapper& wrapper; | ||||
| FakeMouseMoveGenerator fakeMouseGenerator; | |||||
| bool resizingChild = false, resizingParent = false; | bool resizingChild = false, resizingParent = false; | ||||
| float editorScaleFactor = 1.0f; | float editorScaleFactor = 1.0f; | ||||
| @@ -35,7 +35,6 @@ | |||||
| #include "../utility/juce_IncludeSystemHeaders.h" | #include "../utility/juce_IncludeSystemHeaders.h" | ||||
| #include "../utility/juce_IncludeModuleHeaders.h" | #include "../utility/juce_IncludeModuleHeaders.h" | ||||
| #include "../utility/juce_FakeMouseMoveGenerator.h" | |||||
| #include "../utility/juce_CarbonVisibility.h" | #include "../utility/juce_CarbonVisibility.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -48,7 +48,6 @@ JUCE_BEGIN_NO_SANITIZE ("vptr") | |||||
| #include "../utility/juce_IncludeSystemHeaders.h" | #include "../utility/juce_IncludeSystemHeaders.h" | ||||
| #include "../utility/juce_IncludeModuleHeaders.h" | #include "../utility/juce_IncludeModuleHeaders.h" | ||||
| #include "../utility/juce_WindowsHooks.h" | #include "../utility/juce_WindowsHooks.h" | ||||
| #include "../utility/juce_FakeMouseMoveGenerator.h" | |||||
| #include "../utility/juce_LinuxMessageThread.h" | #include "../utility/juce_LinuxMessageThread.h" | ||||
| #include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp> | #include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp> | ||||
| #include <juce_audio_processors/format_types/juce_VST3Common.h> | #include <juce_audio_processors/format_types/juce_VST3Common.h> | ||||
| @@ -1929,8 +1928,6 @@ private: | |||||
| { | { | ||||
| setOpaque (true); | setOpaque (true); | ||||
| setBroughtToFrontOnMouseClick (true); | setBroughtToFrontOnMouseClick (true); | ||||
| ignoreUnused (fakeMouseGenerator); | |||||
| } | } | ||||
| ~ContentWrapperComponent() override | ~ContentWrapperComponent() override | ||||
| @@ -2100,7 +2097,6 @@ private: | |||||
| private: | private: | ||||
| JuceVST3Editor& owner; | JuceVST3Editor& owner; | ||||
| std::unique_ptr<EditorHostContext> editorHostContext; | std::unique_ptr<EditorHostContext> editorHostContext; | ||||
| FakeMouseMoveGenerator fakeMouseGenerator; | |||||
| Rectangle<int> lastBounds; | Rectangle<int> lastBounds; | ||||
| bool resizingChild = false, resizingParent = false; | bool resizingChild = false, resizingParent = false; | ||||
| @@ -1,119 +0,0 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library. | |||||
| Copyright (c) 2020 - Raw Material Software Limited | |||||
| JUCE is an open source library subject to commercial or open-source | |||||
| licensing. | |||||
| By using JUCE, you agree to the terms of both the JUCE 6 End-User License | |||||
| Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). | |||||
| End User License Agreement: www.juce.com/juce-6-licence | |||||
| Privacy Policy: www.juce.com/juce-privacy-policy | |||||
| Or: You may also use this code under the terms of the GPL v3 (see | |||||
| www.gnu.org/licenses). | |||||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||||
| DISCLAIMED. | |||||
| ============================================================================== | |||||
| */ | |||||
| namespace juce | |||||
| { | |||||
| #ifndef DOXYGEN | |||||
| #if JUCE_MAC | |||||
| //============================================================================== | |||||
| // Helper class to workaround windows not getting mouse-moves... | |||||
| class FakeMouseMoveGenerator : private Timer | |||||
| { | |||||
| public: | |||||
| FakeMouseMoveGenerator() | |||||
| { | |||||
| startTimer (1000 / 30); | |||||
| } | |||||
| static bool componentContainsAudioProcessorEditor (Component* comp) noexcept | |||||
| { | |||||
| if (dynamic_cast<AudioProcessorEditor*> (comp) != nullptr) | |||||
| return true; | |||||
| for (auto* child : comp->getChildren()) | |||||
| if (componentContainsAudioProcessorEditor (child)) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| void timerCallback() override | |||||
| { | |||||
| // Workaround for windows not getting mouse-moves... | |||||
| auto screenPos = Desktop::getInstance().getMainMouseSource().getScreenPosition(); | |||||
| if (screenPos != lastScreenPos) | |||||
| { | |||||
| lastScreenPos = screenPos; | |||||
| auto mods = ModifierKeys::currentModifiers; | |||||
| if (! mods.isAnyMouseButtonDown()) | |||||
| { | |||||
| if (auto* comp = Desktop::getInstance().findComponentAt (screenPos.roundToInt())) | |||||
| { | |||||
| if (componentContainsAudioProcessorEditor (comp->getTopLevelComponent())) | |||||
| { | |||||
| safeOldComponent = comp; | |||||
| if (auto* peer = comp->getPeer()) | |||||
| { | |||||
| if (! peer->isFocused()) | |||||
| { | |||||
| peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, | |||||
| peer->globalToLocal (Desktop::getInstance().getMainMouseSource().getRawScreenPosition()), | |||||
| mods, | |||||
| MouseInputSource::invalidPressure, | |||||
| MouseInputSource::invalidOrientation, | |||||
| Time::currentTimeMillis()); | |||||
| } | |||||
| } | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (safeOldComponent != nullptr) | |||||
| { | |||||
| if (auto* peer = safeOldComponent->getPeer()) | |||||
| { | |||||
| peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse, | |||||
| MouseInputSource::offscreenMousePos, | |||||
| mods, | |||||
| MouseInputSource::invalidPressure, | |||||
| MouseInputSource::invalidOrientation, | |||||
| Time::currentTimeMillis()); | |||||
| } | |||||
| } | |||||
| safeOldComponent = nullptr; | |||||
| } | |||||
| } | |||||
| } | |||||
| private: | |||||
| Point<float> lastScreenPos; | |||||
| WeakReference<Component> safeOldComponent; | |||||
| }; | |||||
| #else | |||||
| struct FakeMouseMoveGenerator {}; | |||||
| #endif | |||||
| #endif | |||||
| } // namespace juce | |||||
| @@ -301,11 +301,11 @@ struct Component::ComponentHelpers | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| static bool hitTest (Component& comp, Point<int> localPoint) | |||||
| static bool hitTest (Component& comp, Point<float> localPoint) | |||||
| { | { | ||||
| return isPositiveAndBelow (localPoint.x, comp.getWidth()) | |||||
| && isPositiveAndBelow (localPoint.y, comp.getHeight()) | |||||
| && comp.hitTest (localPoint.x, localPoint.y); | |||||
| const auto intPoint = localPoint.roundToInt(); | |||||
| return Rectangle<int> { comp.getWidth(), comp.getHeight() }.toFloat().contains (localPoint) | |||||
| && comp.hitTest (intPoint.x, intPoint.y); | |||||
| } | } | ||||
| // converts an unscaled position within a peer to the local position within that peer's component | // converts an unscaled position within a peer to the local position within that peer's component | ||||
| @@ -1376,7 +1376,7 @@ bool Component::hitTest (int x, int y) | |||||
| auto& child = *childComponentList.getUnchecked (i); | auto& child = *childComponentList.getUnchecked (i); | ||||
| if (child.isVisible() | if (child.isVisible() | ||||
| && ComponentHelpers::hitTest (child, ComponentHelpers::convertFromParentSpace (child, Point<int> (x, y)))) | |||||
| && ComponentHelpers::hitTest (child, ComponentHelpers::convertFromParentSpace (child, Point<int> (x, y).toFloat()))) | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1405,7 +1405,7 @@ bool Component::contains (Point<int> point) | |||||
| bool Component::containsInternal (Point<float> point) | bool Component::containsInternal (Point<float> point) | ||||
| { | { | ||||
| if (ComponentHelpers::hitTest (*this, point.roundToInt())) | |||||
| if (ComponentHelpers::hitTest (*this, point)) | |||||
| { | { | ||||
| if (parentComponent != nullptr) | if (parentComponent != nullptr) | ||||
| return parentComponent->containsInternal (ComponentHelpers::convertToParentSpace (*this, point)); | return parentComponent->containsInternal (ComponentHelpers::convertToParentSpace (*this, point)); | ||||
| @@ -1441,7 +1441,7 @@ Component* Component::getComponentAt (Point<int> position) | |||||
| Component* Component::getComponentAtInternal (Point<float> position) | Component* Component::getComponentAtInternal (Point<float> position) | ||||
| { | { | ||||
| if (flags.visibleFlag && ComponentHelpers::hitTest (*this, position.roundToInt())) | |||||
| if (flags.visibleFlag && ComponentHelpers::hitTest (*this, position)) | |||||
| { | { | ||||
| for (int i = childComponentList.size(); --i >= 0;) | for (int i = childComponentList.size(); --i >= 0;) | ||||
| { | { | ||||
| @@ -61,6 +61,16 @@ public: | |||||
| [view registerForDraggedTypes: getSupportedDragTypes()]; | [view registerForDraggedTypes: getSupportedDragTypes()]; | ||||
| const auto options = NSTrackingMouseEnteredAndExited | |||||
| | NSTrackingMouseMoved | |||||
| | NSTrackingEnabledDuringMouseDrag | |||||
| | NSTrackingActiveAlways | |||||
| | NSTrackingInVisibleRect; | |||||
| [view addTrackingArea: [[NSTrackingArea alloc] initWithRect: r | |||||
| options: options | |||||
| owner: view | |||||
| userInfo: nil]]; | |||||
| notificationCenter = [NSNotificationCenter defaultCenter]; | notificationCenter = [NSNotificationCenter defaultCenter]; | ||||
| [notificationCenter addObserver: view | [notificationCenter addObserver: view | ||||
| @@ -118,7 +128,6 @@ public: | |||||
| setAlwaysOnTop (true); | setAlwaysOnTop (true); | ||||
| [window setContentView: view]; | [window setContentView: view]; | ||||
| [window setAcceptsMouseMovedEvents: YES]; | |||||
| // We'll both retain and also release this on closing because plugin hosts can unexpectedly | // We'll both retain and also release this on closing because plugin hosts can unexpectedly | ||||
| // close the window for us, and also tend to get cause trouble if setReleasedWhenClosed is NO. | // close the window for us, and also tend to get cause trouble if setReleasedWhenClosed is NO. | ||||
| @@ -392,7 +401,7 @@ public: | |||||
| NSRect viewFrame = [view frame]; | NSRect viewFrame = [view frame]; | ||||
| if (! (isPositiveAndBelow (localPos.getX(), viewFrame.size.width) | if (! (isPositiveAndBelow (localPos.getX(), viewFrame.size.width) | ||||
| && isPositiveAndBelow (localPos.getY(), viewFrame.size.height))) | |||||
| && isPositiveAndBelow (localPos.getY(), viewFrame.size.height))) | |||||
| return false; | return false; | ||||
| if (! SystemStats::isRunningInAppExtensionSandbox()) | if (! SystemStats::isRunningInAppExtensionSandbox()) | ||||
| @@ -630,21 +639,12 @@ public: | |||||
| void redirectMouseEnter (NSEvent* ev) | void redirectMouseEnter (NSEvent* ev) | ||||
| { | { | ||||
| if (shouldIgnoreMouseEnterExit (ev)) | |||||
| return; | |||||
| Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); | |||||
| ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons(); | |||||
| sendMouseEvent (ev); | |||||
| sendMouseEnterExit (ev); | |||||
| } | } | ||||
| void redirectMouseExit (NSEvent* ev) | void redirectMouseExit (NSEvent* ev) | ||||
| { | { | ||||
| if (shouldIgnoreMouseEnterExit (ev)) | |||||
| return; | |||||
| ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons(); | |||||
| sendMouseEvent (ev); | |||||
| sendMouseEnterExit (ev); | |||||
| } | } | ||||
| static float checkDeviceDeltaReturnValue (float v) noexcept | static float checkDeviceDeltaReturnValue (float v) noexcept | ||||
| @@ -906,11 +906,11 @@ public: | |||||
| } | } | ||||
| #endif | #endif | ||||
| drawRect (cg, r, displayScale); | |||||
| drawRectWithContext (cg, r, displayScale); | |||||
| invalidateTransparentWindowShadow(); | invalidateTransparentWindowShadow(); | ||||
| } | } | ||||
| void drawRect (CGContextRef cg, NSRect r, float displayScale) | |||||
| void drawRectWithContext (CGContextRef cg, NSRect r, float displayScale) | |||||
| { | { | ||||
| #if USE_COREGRAPHICS_RENDERING | #if USE_COREGRAPHICS_RENDERING | ||||
| if (usingCoreGraphics) | if (usingCoreGraphics) | ||||
| @@ -1531,10 +1531,13 @@ private: | |||||
| static NSView* createViewInstance(); | static NSView* createViewInstance(); | ||||
| static NSWindow* createWindowInstance(); | static NSWindow* createWindowInstance(); | ||||
| bool shouldIgnoreMouseEnterExit (NSEvent* ev) const | |||||
| void sendMouseEnterExit (NSEvent* ev) | |||||
| { | { | ||||
| auto* eventTrackingArea = [ev trackingArea]; | |||||
| return eventTrackingArea != nil && ! [[view trackingAreas] containsObject: eventTrackingArea]; | |||||
| if (auto* area = [ev trackingArea]) | |||||
| if (! [[view trackingAreas] containsObject: area]) | |||||
| return; | |||||
| sendMouseEvent (ev); | |||||
| } | } | ||||
| static void setOwner (id viewOrWindow, NSViewComponentPeer* newOwner) | static void setOwner (id viewOrWindow, NSViewComponentPeer* newOwner) | ||||
| @@ -1851,30 +1854,30 @@ private: | |||||
| } | } | ||||
| } | } | ||||
| static void asyncMouseDown (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseDown (ev); } | |||||
| static void asyncMouseUp (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseUp (ev); } | |||||
| static void mouseDragged (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseDrag (ev); } | |||||
| static void mouseMoved (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseMove (ev); } | |||||
| static void mouseEntered (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseEnter (ev); } | |||||
| static void mouseExited (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseExit (ev); } | |||||
| static void scrollWheel (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMouseWheel (ev); } | |||||
| static void magnify (id self, SEL, NSEvent* ev) { if (auto* p = getOwner (self)) p->redirectMagnify (ev); } | |||||
| static void copy (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectCopy (s); } | |||||
| static void paste (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectPaste (s); } | |||||
| static void cut (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectCut (s); } | |||||
| static void selectAll (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectSelectAll (s); } | |||||
| static void willMoveToWindow (id self, SEL, NSWindow* w) { if (auto* p = getOwner (self)) p->redirectWillMoveToWindow (w); } | |||||
| static void asyncMouseDown (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDown, ev); } | |||||
| static void asyncMouseUp (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseUp, ev); } | |||||
| static void mouseDragged (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseDrag, ev); } | |||||
| static void mouseMoved (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseMove, ev); } | |||||
| static void mouseEntered (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseEnter, ev); } | |||||
| static void mouseExited (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseExit, ev); } | |||||
| static void scrollWheel (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMouseWheel, ev); } | |||||
| static void magnify (id self, SEL, NSEvent* ev) { callOnOwner (self, &NSViewComponentPeer::redirectMagnify, ev); } | |||||
| static void copy (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectCopy, s); } | |||||
| static void paste (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectPaste, s); } | |||||
| static void cut (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectCut, s); } | |||||
| static void selectAll (id self, SEL, NSObject* s) { callOnOwner (self, &NSViewComponentPeer::redirectSelectAll, s); } | |||||
| static void willMoveToWindow (id self, SEL, NSWindow* w) { callOnOwner (self, &NSViewComponentPeer::redirectWillMoveToWindow, w); } | |||||
| static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; } | static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; } | ||||
| static BOOL wantsDefaultClipping (id, SEL) { return YES; } // (this is the default, but may want to customise it in future) | static BOOL wantsDefaultClipping (id, SEL) { return YES; } // (this is the default, but may want to customise it in future) | ||||
| static BOOL worksWhenModal (id self, SEL) { if (auto* p = getOwner (self)) return p->worksWhenModal(); return NO; } | static BOOL worksWhenModal (id self, SEL) { if (auto* p = getOwner (self)) return p->worksWhenModal(); return NO; } | ||||
| static void drawRect (id self, SEL, NSRect r) { if (auto* p = getOwner (self)) p->drawRect (r); } | |||||
| static void frameChanged (id self, SEL, NSNotification*) { if (auto* p = getOwner (self)) p->redirectMovedOrResized(); } | |||||
| static void viewDidMoveToWindow (id self, SEL) { if (auto* p = getOwner (self)) p->viewMovedToWindow(); } | |||||
| static void dismissModals (id self, SEL) { if (auto* p = getOwner (self)) p->dismissModals(); } | |||||
| static void becomeKey (id self, SEL) { if (auto* p = getOwner (self)) p->becomeKey(); } | |||||
| static void resignKey (id self, SEL) { if (auto* p = getOwner (self)) p->resignKey(); } | |||||
| static void drawRect (id self, SEL, NSRect r) { callOnOwner (self, &NSViewComponentPeer::drawRect, r); } | |||||
| static void frameChanged (id self, SEL, NSNotification*) { callOnOwner (self, &NSViewComponentPeer::redirectMovedOrResized); } | |||||
| static void viewDidMoveToWindow (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::viewMovedToWindow); } | |||||
| static void dismissModals (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::dismissModals); } | |||||
| static void becomeKey (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::becomeKey); } | |||||
| static void resignKey (id self, SEL) { callOnOwner (self, &NSViewComponentPeer::resignKey); } | |||||
| static BOOL isFlipped (id, SEL) { return true; } | static BOOL isFlipped (id, SEL) { return true; } | ||||
| @@ -2075,23 +2078,18 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| static void flagsChanged (id self, SEL, NSEvent* ev) | static void flagsChanged (id self, SEL, NSEvent* ev) | ||||
| { | { | ||||
| if (auto* owner = getOwner (self)) | |||||
| owner->redirectModKeyChange (ev); | |||||
| callOnOwner (self, &NSViewComponentPeer::redirectModKeyChange, ev); | |||||
| } | } | ||||
| static BOOL becomeFirstResponder (id self, SEL) | static BOOL becomeFirstResponder (id self, SEL) | ||||
| { | { | ||||
| if (auto* owner = getOwner (self)) | |||||
| owner->viewFocusGain(); | |||||
| callOnOwner (self, &NSViewComponentPeer::viewFocusGain); | |||||
| return YES; | return YES; | ||||
| } | } | ||||
| static BOOL resignFirstResponder (id self, SEL) | static BOOL resignFirstResponder (id self, SEL) | ||||
| { | { | ||||
| if (auto* owner = getOwner (self)) | |||||
| owner->viewFocusLoss(); | |||||
| callOnOwner (self, &NSViewComponentPeer::viewFocusLoss); | |||||
| return YES; | return YES; | ||||
| } | } | ||||
| @@ -2123,8 +2121,7 @@ private: | |||||
| static void draggingExited (id self, SEL, id<NSDraggingInfo> sender) | static void draggingExited (id self, SEL, id<NSDraggingInfo> sender) | ||||
| { | { | ||||
| if (auto* owner = getOwner (self)) | |||||
| owner->sendDragCallback (1, sender); | |||||
| callOnOwner (self, &NSViewComponentPeer::sendDragCallback, 1, sender); | |||||
| } | } | ||||
| static BOOL prepareForDragOperation (id, SEL, id<NSDraggingInfo>) | static BOOL prepareForDragOperation (id, SEL, id<NSDraggingInfo>) | ||||
| @@ -2201,6 +2198,13 @@ private: | |||||
| return sendSuperclassMessage<BOOL> (self, s, event); | return sendSuperclassMessage<BOOL> (self, s, event); | ||||
| } | } | ||||
| template <typename Func, typename... Args> | |||||
| static void callOnOwner (id self, Func&& func, Args&&... args) | |||||
| { | |||||
| if (auto* owner = getOwner (self)) | |||||
| (owner->*func) (std::forward<Args> (args)...); | |||||
| } | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||