1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-21 01:24:21 +00:00

HWNDComponentPeer: Dismiss modals more proactively

This change makes heavyweight views listen to window events from higher
in the window hierarchy. If a move or resize event from higher in the
hierarchy is encountered, blocking modal components will be dismissed.

This patch should resolve an issue where the popupmenu for a combobox
could become 'stranded' if the plugin window was moved while the box was
open.
This commit is contained in:
reuk 2021-01-07 18:00:13 +00:00
parent 60f756e22f
commit 85facf6d6e
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11

View file

@ -3841,15 +3841,13 @@ private:
bool sendInputAttemptWhenModalMessage()
{
if (component.isCurrentlyBlockedByAnotherModalComponent())
{
if (Component* const current = Component::getCurrentlyModalComponent())
current->inputAttemptWhenModal();
if (! component.isCurrentlyBlockedByAnotherModalComponent())
return false;
return true;
}
if (auto* current = Component::getCurrentlyModalComponent())
current->inputAttemptWhenModal();
return false;
return true;
}
//==============================================================================
@ -4074,6 +4072,73 @@ private:
stopTimer();
}
static bool isAncestor (HWND outer, HWND inner)
{
if (outer == nullptr || inner == nullptr)
return false;
if (outer == inner)
return true;
return isAncestor (outer, GetAncestor (inner, GA_PARENT));
}
void windowShouldDismissModals (HWND originator)
{
if (isAncestor (originator, hwnd))
sendInputAttemptWhenModalMessage();
}
// Unfortunately SetWindowsHookEx only allows us to register a static function as a hook.
// To get around this, we keep a static list of listeners which are interested in
// top-level window events, and notify all of these listeners from the callback.
class TopLevelModalDismissBroadcaster
{
public:
TopLevelModalDismissBroadcaster()
: hook (SetWindowsHookEx (WH_CALLWNDPROC,
callWndProc,
(HINSTANCE) juce::Process::getCurrentModuleInstanceHandle(),
GetCurrentThreadId()))
{}
~TopLevelModalDismissBroadcaster() noexcept
{
UnhookWindowsHookEx (hook);
}
private:
static void processMessage (int nCode, const CWPSTRUCT* info)
{
if (nCode < 0 || info == nullptr)
return;
constexpr UINT events[] { WM_MOVE,
WM_SIZE,
WM_WINDOWPOSCHANGED,
WM_NCPOINTERDOWN,
WM_NCLBUTTONDOWN,
WM_NCRBUTTONDOWN,
WM_NCMBUTTONDOWN };
if (std::find (std::begin (events), std::end (events), info->message) == std::end (events))
return;
for (auto i = ComponentPeer::getNumPeers(); --i >= 0;)
if (auto* hwndPeer = dynamic_cast<HWNDComponentPeer*> (ComponentPeer::getPeer (i)))
hwndPeer->windowShouldDismissModals (info->hwnd);
}
static LRESULT CALLBACK callWndProc (int nCode, WPARAM wParam, LPARAM lParam)
{
processMessage (nCode, reinterpret_cast<CWPSTRUCT*> (lParam));
return CallNextHookEx ({}, nCode, wParam, lParam);
}
HHOOK hook;
};
SharedResourcePointer<TopLevelModalDismissBroadcaster> modalDismissBroadcaster;
IMEHandler imeHandler;
//==============================================================================