From f19e4d1c04a734334d6a2f7cb4c1eb71fcdc3862 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Sun, 9 Jan 2011 13:46:36 +0000 Subject: [PATCH] Added workarounds for mouse-wheel events in win32 VSTs and mouse-moves in carbon AUs and VSTs. Fixed a problem when swapping between carbon/cocoa views in AUs. --- .../wrapper/AU/juce_AU_Wrapper.mm | 62 ++++++++----------- .../wrapper/VST/juce_VST_Wrapper.cpp | 54 +++++++++++++--- .../wrapper/juce_PluginHeaders.h | 45 ++++++++++++++ juce_amalgamated.cpp | 3 - juce_amalgamated.h | 2 +- src/audio/processors/juce_AudioProcessor.cpp | 3 - src/audio/processors/juce_AudioProcessor.h | 2 +- 7 files changed, 120 insertions(+), 51 deletions(-) diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index 1ddc87ae0b..84c58bfb11 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -951,15 +951,13 @@ private: }; //============================================================================== -class EditorCompHolder : public Component, - public ComponentListener +class EditorCompHolder : public Component { public: EditorCompHolder (AudioProcessorEditor* const editor) { setSize (editor->getWidth(), editor->getHeight()); addAndMakeVisible (editor); - editor->addComponentListener (this); #if ! JucePlugin_EditorRequiresKeyboardFocus setWantsKeyboardFocus (false); @@ -974,11 +972,11 @@ public: // have been transferred to another parent which takes over ownership. } - void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) + void childBoundsChanged (Component*) { Component* editor = getChildComponent(0); - if (editor != 0 && wasResized) + if (editor != 0) { const int w = jmax (32, editor->getWidth()); const int h = jmax (32, editor->getHeight()); @@ -988,13 +986,16 @@ public: NSView* view = (NSView*) getWindowHandle(); NSRect r = [[view superview] frame]; - r.size.width = component.getWidth(); - r.size.height = component.getHeight(); + r.size.width = editor->getWidth(); + r.size.height = editor->getHeight(); [[view superview] setFrame: r]; [view setFrame: NSMakeRect (0, 0, editor->getWidth(), editor->getHeight())]; [view setNeedsDisplay: YES]; } } + +private: + JUCE_DECLARE_NON_COPYABLE (EditorCompHolder); }; //============================================================================== @@ -1044,6 +1045,7 @@ public: // is trying to delete our plugin.. jassert (Component::getCurrentlyModalComponent() == 0); + [[NSNotificationCenter defaultCenter] removeObserver: self]; [self deleteEditor]; jassert (activeUIs.contains (self)); @@ -1204,6 +1206,8 @@ public: void* getEventListenerUserData() const { return mEventListenerUserData; } private: + FakeMouseMoveGenerator fakeMouseGenerator; + void deleteUI() { if (windowComp != 0) @@ -1223,26 +1227,25 @@ private: //============================================================================== // Uses a child NSWindow to sit in front of a HIView and display our component - class ComponentInHIView : public Component, - public ComponentListener + class ComponentInHIView : public Component { public: //============================================================================== - ComponentInHIView (Component* const editor_, HIViewRef parentHIView) + ComponentInHIView (AudioProcessorEditor* const editor_, HIViewRef parentHIView) : parentView (parentHIView), editor (editor_), recursive (false) { JUCE_AUTORELEASEPOOL - jassert (editor != 0); - addAndMakeVisible (editor); + jassert (editor_ != 0); + addAndMakeVisible (&editor); setOpaque (true); setVisible (true); setBroughtToFrontOnMouseClick (true); - setSize (editor->getWidth(), editor->getHeight()); - SizeControl (parentHIView, editor->getWidth(), editor->getHeight()); + setSize (editor.getWidth(), editor.getHeight()); + SizeControl (parentHIView, editor.getWidth(), editor.getHeight()); WindowRef windowRef = HIViewGetWindow (parentHIView); hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef]; @@ -1280,16 +1283,10 @@ private: NewEventHandlerUPP (windowVisibilityBodge), GetEventTypeCount (eventsToCatch), eventsToCatch, (void*) hostWindow, 0); - - editor->addComponentListener (this); } ~ComponentInHIView() { - jassert (isParentOf (editor)); // you mustn't remove your editor from its parent! - - editor->removeComponentListener (this); - JUCE_AUTORELEASEPOOL NSWindow* pluginWindow = [((NSView*) getWindowHandle()) window]; @@ -1298,8 +1295,6 @@ private: [hostWindow release]; hostWindow = 0; - - editor = 0; } void updateWindowPos() @@ -1330,27 +1325,24 @@ private: void paint (Graphics& g) {} - void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) + void childBoundsChanged (Component*) { if (! recursive) { recursive = true; - if (editor != 0 && wasResized) - { - const int w = jmax (32, editor->getWidth()); - const int h = jmax (32, editor->getHeight()); + const int w = jmax (32, editor.getWidth()); + const int h = jmax (32, editor.getHeight()); - SizeControl (parentView, w, h); + SizeControl (parentView, w, h); - if (getWidth() != w || getHeight() != h) - setSize (w, h); + if (getWidth() != w || getHeight() != h) + setSize (w, h); - editor->repaint(); + editor.repaint(); - updateWindowPos(); - addSubWindow(); // (need this for AULab) - } + updateWindowPos(); + addSubWindow(); // (need this for AULab) recursive = false; } @@ -1378,7 +1370,7 @@ private: private: HIViewRef parentView; NSWindow* hostWindow; - ScopedPointer editor; + EditorCompHolder editor; bool recursive; /* When you wrap a WindowRef as an NSWindow, it seems to bugger up the HideWindow diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index ac25e9cbe7..da0431869d 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -185,15 +185,10 @@ namespace GetClassName (parent, windowType, 31); if (String (windowType).equalsIgnoreCase ("MDIClient")) - { - w = parent; - break; - } + return parent; - RECT windowPos; + RECT windowPos, parentPos; GetWindowRect (w, &windowPos); - - RECT parentPos; GetWindowRect (parent, &parentPos); const int dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); @@ -210,6 +205,42 @@ namespace return w; } + + //============================================================================== + static HHOOK mouseWheelHook = 0; + static int mouseHookUsers = 0; + + LRESULT CALLBACK mouseWheelHookCallback (int nCode, WPARAM wParam, LPARAM lParam) + { + if (nCode >= 0 && wParam == WM_MOUSEWHEEL) + { + const MSLLHOOKSTRUCT& hs = *(MSLLHOOKSTRUCT*) lParam; + + Component* const comp = Desktop::getInstance().findComponentAt (Point (hs.pt.x, + hs.pt.y)); + if (comp != 0 && comp->getWindowHandle() != 0) + return PostMessage ((HWND) comp->getWindowHandle(), WM_MOUSEWHEEL, + hs.mouseData & 0xffff0000, (hs.pt.x & 0xffff) | (hs.pt.y << 16)); + } + + return CallNextHookEx (mouseWheelHook, nCode, wParam, lParam); + } + + void registerMouseWheelHook() + { + if (mouseHookUsers++ == 0) + mouseWheelHook = SetWindowsHookEx (WH_MOUSE_LL, mouseWheelHookCallback, + (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), 0); + } + + void unregisterMouseWheelHook() + { + if (--mouseHookUsers == 0 && mouseWheelHook != 0) + { + UnhookWindowsHookEx (mouseWheelHook); + mouseWheelHook = 0; + } + } } //============================================================================== @@ -1288,14 +1319,20 @@ public: editor->setTopLeftPosition (0, 0); addAndMakeVisible (editor); - #if JUCE_WIN + #if JUCE_WINDOWS if (! getHostType().isReceptor()) addMouseListener (this, true); + + registerMouseWheelHook(); #endif } ~EditorCompWrapper() { + #if JUCE_WINDOWS + unregisterMouseWheelHook(); + #endif + deleteAllChildren(); // note that we can't use a ScopedPointer because the editor may // have been transferred to another parent which takes over ownership. } @@ -1379,6 +1416,7 @@ public: private: //============================================================================== JuceVSTWrapper& wrapper; + FakeMouseMoveGenerator fakeMouseGenerator; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorCompWrapper); }; diff --git a/extras/audio plugins/wrapper/juce_PluginHeaders.h b/extras/audio plugins/wrapper/juce_PluginHeaders.h index 1bd66a362d..e8633a452e 100644 --- a/extras/audio plugins/wrapper/juce_PluginHeaders.h +++ b/extras/audio plugins/wrapper/juce_PluginHeaders.h @@ -25,3 +25,48 @@ #include "juce_IncludeCharacteristics.h" #include "../../../juce_amalgamated.h" + + +#if JUCE_MAC && JUCE_SUPPORT_CARBON + +// Helper class to workaround carbon windows not getting mouse-moves.. +class FakeMouseMoveGenerator : public Timer +{ +public: + FakeMouseMoveGenerator() + { + startTimer (1000 / 30); + } + + void timerCallback() + { + // workaround for carbon windows not getting mouse-moves.. + const Point screenPos (Desktop::getInstance().getMainMouseSource().getScreenPosition()); + + if (screenPos != lastScreenPos) + { + lastScreenPos = screenPos; + const ModifierKeys mods (ModifierKeys::getCurrentModifiers()); + + if (! mods.isAnyMouseButtonDown()) + { + Component* comp = Desktop::getInstance().findComponentAt (screenPos); + + if (comp != 0) + { + ComponentPeer* const peer = comp->getPeer(); + + if (peer != 0 && ! peer->isFocused()) + peer->handleMouseEvent (0, screenPos - peer->getScreenPosition(), mods, Time::currentTimeMillis()); + } + } + } + } + +private: + Point lastScreenPos; +}; + +#else +struct FakeMouseMoveGenerator {}; +#endif diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index b95cda5a8c..95900f79bf 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -35673,7 +35673,6 @@ BEGIN_JUCE_NAMESPACE AudioProcessor::AudioProcessor() : playHead (0), - activeEditor (0), sampleRate (0), blockSize (0), numInputChannels (0), @@ -35855,8 +35854,6 @@ void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) thr { const ScopedLock sl (callbackLock); - jassert (activeEditor == editor); - if (activeEditor == editor) activeEditor = 0; } diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 9b34cd9d3f..840713360c 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -41698,7 +41698,7 @@ protected: private: Array listeners; - AudioProcessorEditor* activeEditor; + Component::SafePointer activeEditor; double sampleRate; int blockSize, numInputChannels, numOutputChannels, latencySamples; bool suspended, nonRealtime; diff --git a/src/audio/processors/juce_AudioProcessor.cpp b/src/audio/processors/juce_AudioProcessor.cpp index dd2b4863d4..14b6fd25c6 100644 --- a/src/audio/processors/juce_AudioProcessor.cpp +++ b/src/audio/processors/juce_AudioProcessor.cpp @@ -35,7 +35,6 @@ BEGIN_JUCE_NAMESPACE //============================================================================== AudioProcessor::AudioProcessor() : playHead (0), - activeEditor (0), sampleRate (0), blockSize (0), numInputChannels (0), @@ -218,8 +217,6 @@ void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) thr { const ScopedLock sl (callbackLock); - jassert (activeEditor == editor); - if (activeEditor == editor) activeEditor = 0; } diff --git a/src/audio/processors/juce_AudioProcessor.h b/src/audio/processors/juce_AudioProcessor.h index 0fde4ae02c..ae2dcd7d10 100644 --- a/src/audio/processors/juce_AudioProcessor.h +++ b/src/audio/processors/juce_AudioProcessor.h @@ -580,7 +580,7 @@ protected: private: Array listeners; - AudioProcessorEditor* activeEditor; + Component::SafePointer activeEditor; double sampleRate; int blockSize, numInputChannels, numOutputChannels, latencySamples; bool suspended, nonRealtime;