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:
parent
60f756e22f
commit
85facf6d6e
1 changed files with 72 additions and 7 deletions
|
|
@ -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;
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue