Reimplement wxPopupWindow as a WS_POPUP window under MSW

Don't use the child window of the desktop window for popup windows under
MSW, while this worked in simplest cases, it didn't allow having
functional controls inside a wxPopupWindow as e.g. wxTextCtrl didn't
accept input it at all if created as a child of such window.

Instead, switch to using a top-level window, with WS_POPUP style, and
fix the problem with the loss of activation by explicitly pretending to
still be active in the owner window when losing activation to our own
popup (thanks to Barmak Shemirani for providing this solution).

Also use an MSW-specific and much simpler implementation of detecting
when the popup should be dismissed in wxPopupTransientWindow: instead of
capturing mouse or tracking focus, just react to activation loss
directly.

Add a wxTextCtrl to the popup in samples/popup to show that editing it
works now.
This commit is contained in:
Vadim Zeitlin
2018-10-20 18:44:18 +02:00
parent 17055fb8c6
commit 56c4191168
6 changed files with 206 additions and 109 deletions

View File

@@ -60,6 +60,7 @@
#include "wx/hashmap.h"
#include "wx/evtloop.h"
#include "wx/popupwin.h"
#include "wx/power.h"
#include "wx/scopeguard.h"
#include "wx/sysopt.h"
@@ -134,6 +135,10 @@
extern wxMenu *wxCurrentPopupMenu;
#endif
#if wxUSE_POPUPWIN
extern wxPopupWindow* wxCurrentPopupWindow;
#endif // wxUSE_POPUPWIN
#if wxUSE_UXTHEME
// This is a hack used by the owner-drawn wxButton implementation to ensure
// that the brush used for erasing its background is correctly aligned with the
@@ -3677,6 +3682,23 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
}
break;
case WM_NCACTIVATE:
// When we're losing activation to our own popup window, we want to
// retain the "active" appearance of the title bar, as dropping
// down a combobox popup shouldn't deactivate the window containing
// the combobox, for example. Explicitly calling DefWindowProc() to
// draw the window as active seems to be the only way of achieving
// this (thanks to Barmak Shemirani for suggesting it at
// https://stackoverflow.com/a/52808753/15275).
if ( !wParam &&
wxCurrentPopupWindow &&
wxCurrentPopupWindow->MSWGetOwner() == this )
{
rc.result = MSWDefWindowProc(message, TRUE, lParam);
processed = true;
}
break;
#if wxUSE_UXTHEME
// If we want the default themed border then we need to draw it ourselves
case WM_NCCALCSIZE: