diff --git a/include/wx/msw/popupwin.h b/include/wx/msw/popupwin.h index d41dda58e5..bba24abfae 100644 --- a/include/wx/msw/popupwin.h +++ b/include/wx/msw/popupwin.h @@ -25,11 +25,15 @@ public: bool Create(wxWindow *parent, int flags = wxBORDER_NONE); + virtual void SetFocus() wxOVERRIDE; virtual bool Show(bool show = true) wxOVERRIDE; // return the style to be used for the popup windows virtual WXDWORD MSWGetStyle(long flags, WXDWORD *exstyle) const wxOVERRIDE; + // get the HWND to be used as parent of this window with CreateWindow() + virtual WXHWND MSWGetParent() const wxOVERRIDE; + // Implementation only from now on. diff --git a/include/wx/popupwin.h b/include/wx/popupwin.h index 3d20bf4a7b..e8c0dd9242 100644 --- a/include/wx/popupwin.h +++ b/include/wx/popupwin.h @@ -15,6 +15,15 @@ #if wxUSE_POPUPWIN +// ---------------------------------------------------------------------------- +// wxPopupWindow specific flags +// ---------------------------------------------------------------------------- + +// This flag can be used in MSW if some controls are not working with the +// default popup style. +#define wxPU_CONTAINS_CONTROLS 0x0001 + + #include "wx/nonownedwnd.h" // ---------------------------------------------------------------------------- @@ -124,6 +133,13 @@ public: wxPopupTransientWindow() { } wxPopupTransientWindow(wxWindow *parent, int style = wxBORDER_NONE) { Create(parent, style); } + bool Create(wxWindow *parent, int style = wxBORDER_NONE) + { + return wxPopupTransientWindowBase::Create + ( + parent, style | wxPU_CONTAINS_CONTROLS + ); + } // Implement base class pure virtuals. virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE; diff --git a/interface/wx/popupwin.h b/interface/wx/popupwin.h index 01af6cfa63..b1a00a71f6 100644 --- a/interface/wx/popupwin.h +++ b/interface/wx/popupwin.h @@ -11,6 +11,19 @@ A special kind of top level window used for popup menus, combobox popups and such. + @beginStyleTable + @style{wxPU_CONTAINS_CONTROLS} + By default in wxMSW, a popup window will not take focus from its parent + window. However many standard controls, including common ones such as + wxTextCtrl, need focus to function correctly and will not work when + placed on a default popup. This flag can be used to make the popup take + focus and let all controls work but at the price of not allowing the + parent window to keep focus while the popup is shown, which can also be + sometimes desirable. This style is currently only implemented in MSW + and simply does nothing under the other platforms (it's new since + wxWidgets 3.1.3). + @endStyleTable + @library{wxcore} @category{managedwnd} diff --git a/src/msw/popupwin.cpp b/src/msw/popupwin.cpp index 3784c52a98..525fd29469 100644 --- a/src/msw/popupwin.cpp +++ b/src/msw/popupwin.cpp @@ -64,13 +64,24 @@ WXDWORD wxPopupWindow::MSWGetStyle(long flags, WXDWORD *exstyle) const // we only honour the border flags, the others don't make sense for us WXDWORD style = wxWindow::MSWGetStyle(flags & wxBORDER_MASK, exstyle); - // We need to be a popup (i.e. not a child) window in order to not be - // confined to the parent window area, as is required for a drop down, for - // example. Old implementation used WS_CHILD and made this window a child - // of the desktop window, but this resulted in problems with handling input - // in the popup children, and so was changed to the current version. - style &= ~WS_CHILD; - style |= WS_POPUP; + // wxMSW uses 2 rather different implementations of wxPopupWindow + // internally, each one with its own limitations, so we allow specifying + // wxPU_CONTAINS_CONTROLS flag to select which one is used. The default is + // to use a child window of the desktop for the popup, which is compatible + // with the previous wxWidgets versions and works well for simple popups, + // but many standard controls can't work as children of such a window + // because it doesn't accept focus. So an alternative implementation for + // the popups that will contain such controls is available, but this one + // has problems due to the fact that it does take focus and not only can + // (and does) this break existing code, but it also prevents the parent + // window from keeping focus while showing the popup, as must be done when + // using auto-completion tooltips, for example. So neither implementation + // can be used in all cases and you have to explicitly choose your poison. + if ( HasFlag(wxPU_CONTAINS_CONTROLS) ) + { + style &= ~WS_CHILD; + style |= WS_POPUP; + } if ( exstyle ) { @@ -81,6 +92,31 @@ WXDWORD wxPopupWindow::MSWGetStyle(long flags, WXDWORD *exstyle) const return style; } +WXHWND wxPopupWindow::MSWGetParent() const +{ + if ( HasFlag(wxPU_CONTAINS_CONTROLS) ) + { + return wxPopupWindowBase::MSWGetParent(); + } + else + { + // we must be a child of the desktop to be able to extend beyond the + // parent window client area (like the comboboxes drop downs do) + return (WXHWND)::GetDesktopWindow(); + } +} + +void wxPopupWindow::SetFocus() +{ + // Focusing on a popup window does not work on MSW unless WS_POPUP style + // is set. Since this is only the case if the style wxPU_CONTAINS_CONTROLS + // is used, we'll handle the focus in that case and otherwise do nothing. + if ( HasFlag(wxPU_CONTAINS_CONTROLS) ) + { + wxPopupWindowBase::SetFocus(); + } +} + bool wxPopupWindow::Show(bool show) { // It's important to update wxCurrentPopupWindow before showing the window, @@ -88,7 +124,30 @@ bool wxPopupWindow::Show(bool show) // from inside Show() so that it knows to remain [appearing] active. wxCurrentPopupWindow = show ? this : NULL; - return wxPopupWindowBase::Show(show); + if ( HasFlag(wxPU_CONTAINS_CONTROLS) ) + { + return wxPopupWindowBase::Show(show); + } + else + { + if ( !wxWindowMSW::Show(show) ) + return false; + + if ( show ) + { + // raise to top of z order + if ( !::SetWindowPos(GetHwnd(), HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE) ) + { + wxLogLastError(wxT("SetWindowPos")); + } + + // and set it as the foreground window so the mouse can be captured + ::SetForegroundWindow(GetHwnd()); + } + + return true; + } } // ----------------------------------------------------------------------------