Merge branch 'msw-dismiss-unfocused-popup'
Allow wxPopupTransientWindow to work without wxPU_CONTAINS_CONTROLS too in wxMSW and don't use wxPU_CONTAINS_CONTROLS by default, notably allowing wxTipWindow to be shown without stealing focus. See https://github.com/wxWidgets/wxWidgets/pull/1942 Closes #18636.
This commit is contained in:
		| @@ -40,6 +40,10 @@ public: | ||||
|     // Return the top level window parent of this popup or null. | ||||
|     wxWindow* MSWGetOwner() const { return m_owner; } | ||||
|  | ||||
|     // This is a way to notify non-wxPU_CONTAINS_CONTROLS windows about the | ||||
|     // events that should result in their dismissal. | ||||
|     virtual void MSWDismissUnfocusedPopup() { } | ||||
|  | ||||
| private: | ||||
|     wxWindow* m_owner; | ||||
|  | ||||
|   | ||||
| @@ -133,13 +133,6 @@ 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; | ||||
| @@ -151,6 +144,9 @@ public: | ||||
|                                   WXWPARAM wParam, | ||||
|                                   WXLPARAM lParam) wxOVERRIDE; | ||||
|  | ||||
|     // Override to dismiss the popup. | ||||
|     virtual void MSWDismissUnfocusedPopup() wxOVERRIDE; | ||||
|  | ||||
| private: | ||||
|     void DismissOnDeactivate(); | ||||
|  | ||||
|   | ||||
| @@ -58,6 +58,10 @@ | ||||
|     #include "wx/tipdlg.h" | ||||
| #endif // wxUSE_STARTUP_TIPS | ||||
|  | ||||
| #if wxUSE_TIPWINDOW | ||||
|     #include "wx/tipwin.h" | ||||
| #endif // wxUSE_TIPWINDOW | ||||
|  | ||||
| #if wxUSE_PROGRESSDLG | ||||
| #if wxUSE_STOPWATCH && wxUSE_LONGLONG | ||||
|     #include "wx/datetime.h"      // wxDateTime | ||||
| @@ -280,6 +284,10 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) | ||||
|     EVT_MENU(DIALOGS_NOTIFY_MSG,                    MyFrame::OnNotifMsg) | ||||
| #endif // wxUSE_NOTIFICATION_MESSAGE | ||||
|  | ||||
| #if wxUSE_TIPWINDOW | ||||
|     EVT_MENU(DIALOGS_SHOW_TIP,                      MyFrame::OnShowTip) | ||||
|     EVT_UPDATE_UI(DIALOGS_SHOW_TIP,                 MyFrame::OnUpdateShowTipUI) | ||||
| #endif // wxUSE_TIPWINDOW | ||||
| #if wxUSE_RICHTOOLTIP | ||||
|     EVT_MENU(DIALOGS_RICHTIP_DIALOG,                MyFrame::OnRichTipDialog) | ||||
| #endif // wxUSE_RICHTOOLTIP | ||||
| @@ -590,6 +598,10 @@ bool MyApp::OnInit() | ||||
| #endif // wxUSE_NOTIFICATION_MESSAGE | ||||
|     menuDlg->AppendSubMenu(menuNotif, "&User notifications"); | ||||
|  | ||||
| #if wxUSE_TIPWINDOW | ||||
|     menuDlg->AppendCheckItem(DIALOGS_SHOW_TIP, "Show &tip window\tShift-Ctrl-H"); | ||||
| #endif // wxUSE_TIPWINDOW | ||||
|  | ||||
| #if wxUSE_RICHTOOLTIP | ||||
|     menuDlg->Append(DIALOGS_RICHTIP_DIALOG, "Rich &tooltip dialog...\tCtrl-H"); | ||||
|     menuDlg->AppendSeparator(); | ||||
| @@ -713,6 +725,10 @@ MyFrame::MyFrame(const wxString& title) | ||||
|     SetOwnBackgroundColour(m_canvas->GetBackgroundColour()); | ||||
| #endif // wxUSE_INFOBAR | ||||
|  | ||||
| #if wxUSE_TIPWINDOW | ||||
|     m_tipWindow = NULL; | ||||
| #endif // wxUSE_TIPWINDOW | ||||
|  | ||||
| #ifdef __WXMSW__ | ||||
|     // Test MSW-specific function allowing to access the "system" menu. | ||||
|     wxMenu * const menu = MSWGetSystemMenu(); | ||||
| @@ -2389,6 +2405,35 @@ void MyFrame::OnNotifMsg(wxCommandEvent& WXUNUSED(event)) | ||||
|  | ||||
| #endif // wxUSE_NOTIFICATION_MESSAGE | ||||
|  | ||||
| #if wxUSE_TIPWINDOW | ||||
|  | ||||
| void MyFrame::OnShowTip(wxCommandEvent& WXUNUSED(event)) | ||||
| { | ||||
|     if ( m_tipWindow ) | ||||
|     { | ||||
|         m_tipWindow->Close(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         m_tipWindow = new wxTipWindow | ||||
|                           ( | ||||
|                             this, | ||||
|                             "This is just some text to be shown in the tip " | ||||
|                             "window, broken into multiple lines, each less " | ||||
|                             "than 60 logical pixels wide.", | ||||
|                             FromDIP(60), | ||||
|                             &m_tipWindow | ||||
|                           ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void MyFrame::OnUpdateShowTipUI(wxUpdateUIEvent& event) | ||||
| { | ||||
|     event.Check(m_tipWindow != NULL); | ||||
| } | ||||
|  | ||||
| #endif // wxUSE_TIPWINDOW | ||||
|  | ||||
| #if wxUSE_RICHTOOLTIP | ||||
|  | ||||
| #include "wx/richtooltip.h" | ||||
|   | ||||
| @@ -544,6 +544,13 @@ private: | ||||
|     SettingsData m_settingsData; | ||||
| #endif // USE_SETTINGS_DIALOG | ||||
|  | ||||
| #if wxUSE_TIPWINDOW | ||||
|     void OnShowTip(wxCommandEvent& event); | ||||
|     void OnUpdateShowTipUI(wxUpdateUIEvent& event); | ||||
|  | ||||
|     wxTipWindow *m_tipWindow; | ||||
| #endif // wxUSE_TIPWINDOW | ||||
|  | ||||
|     wxDECLARE_EVENT_TABLE(); | ||||
| }; | ||||
|  | ||||
| @@ -623,6 +630,7 @@ enum | ||||
|     DIALOGS_REPLACE, | ||||
|     DIALOGS_REQUEST, | ||||
|     DIALOGS_NOTIFY_MSG, | ||||
|     DIALOGS_SHOW_TIP, | ||||
|     DIALOGS_RICHTIP_DIALOG, | ||||
|     DIALOGS_PROPERTY_SHEET, | ||||
|     DIALOGS_PROPERTY_SHEET_TOOLBOOK, | ||||
|   | ||||
| @@ -108,7 +108,9 @@ wxBEGIN_EVENT_TABLE(SimpleTransientPopup,wxPopupTransientWindow) | ||||
| wxEND_EVENT_TABLE() | ||||
|  | ||||
| SimpleTransientPopup::SimpleTransientPopup( wxWindow *parent, bool scrolled ) | ||||
|                      :wxPopupTransientWindow( parent ) | ||||
|                      :wxPopupTransientWindow( parent, | ||||
|                                               wxBORDER_NONE | | ||||
|                                               wxPU_CONTAINS_CONTROLS ) | ||||
| { | ||||
|     m_panel = new wxScrolledWindow( this, wxID_ANY ); | ||||
|     m_panel->SetBackgroundColour( *wxLIGHT_GREY ); | ||||
|   | ||||
| @@ -136,7 +136,9 @@ wxTipWindow::wxTipWindow(wxWindow *parent, | ||||
|     // set size, position and show it | ||||
|     m_view = new wxTipWindowView(this); | ||||
|     m_view->Adjust(text, maxLength); | ||||
| #if !wxUSE_POPUPWIN | ||||
|     m_view->SetFocus(); | ||||
| #endif | ||||
|  | ||||
|     int x, y; | ||||
|     wxGetMousePosition(&x, &y); | ||||
|   | ||||
| @@ -180,10 +180,10 @@ void wxPopupTransientWindow::Popup(wxWindow* focus) | ||||
| { | ||||
|     Show(); | ||||
|  | ||||
|     // We can only set focus to one of our children as setting it to another | ||||
|     // window would result in an immediate loss of activation and popup | ||||
|     // disappearance. | ||||
|     if ( focus && IsDescendant(focus) ) | ||||
|     // We can only set focus when using wxPU_CONTAINS_CONTROLS and then only to | ||||
|     // one of our children as setting it to another window would result in an | ||||
|     // immediate loss of activation and popup disappearance. | ||||
|     if ( HasFlag(wxPU_CONTAINS_CONTROLS) && focus && IsDescendant(focus) ) | ||||
|         focus->SetFocus(); | ||||
| } | ||||
|  | ||||
| @@ -195,7 +195,7 @@ void wxPopupTransientWindow::Dismiss() | ||||
| void wxPopupTransientWindow::DismissOnDeactivate() | ||||
| { | ||||
|     // Hide the window automatically when it loses activation. | ||||
|     Dismiss(); | ||||
|     DismissAndNotify(); | ||||
|  | ||||
|     // Activation might have gone to a different window or maybe | ||||
|     // even a different application, don't let our owner continue | ||||
| @@ -210,6 +210,19 @@ void wxPopupTransientWindow::DismissOnDeactivate() | ||||
|     } | ||||
| } | ||||
|  | ||||
| void wxPopupTransientWindow::MSWDismissUnfocusedPopup() | ||||
| { | ||||
|     // When we use wxPU_CONTAINS_CONTROLS, we can react to the popup | ||||
|     // deactivation in MSWHandleMessage(), but if we don't have focus, we don't | ||||
|     // get any events ourselves, so we rely on wxWindow to forward them to us. | ||||
|     if ( !HasFlag(wxPU_CONTAINS_CONTROLS) ) | ||||
|     { | ||||
|         // It doesn't seem necessary to use CallAfter() here, as dismissing | ||||
|         // this window shouldn't affect the focus, as it never has it anyhow. | ||||
|         DismissAndNotify(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool | ||||
| wxPopupTransientWindow::MSWHandleMessage(WXLRESULT *result, | ||||
|                                          WXUINT message, | ||||
|   | ||||
| @@ -3844,6 +3844,42 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result, | ||||
|             } | ||||
|     } | ||||
|  | ||||
|     // Special hook for dismissing the current popup if it's active. It's a bit | ||||
|     // ugly to have to do this here, but the only alternatives seem to be | ||||
|     // installing a WH_CBT hook in wxPopupTransientWindow code, which is not | ||||
|     // really much better. | ||||
| #if wxUSE_POPUPWIN | ||||
|     if ( wxCurrentPopupWindow ) | ||||
|     { | ||||
|         switch ( message ) | ||||
|         { | ||||
|             case WM_NCLBUTTONDOWN: | ||||
|             case WM_NCLBUTTONUP: | ||||
|             case WM_NCLBUTTONDBLCLK: | ||||
|             case WM_NCRBUTTONDOWN: | ||||
|             case WM_NCRBUTTONUP: | ||||
|             case WM_NCRBUTTONDBLCLK: | ||||
|             case WM_NCMBUTTONDOWN: | ||||
|             case WM_NCMBUTTONUP: | ||||
|             case WM_NCMBUTTONDBLCLK: | ||||
|  | ||||
|             case WM_LBUTTONDOWN: | ||||
|             case WM_LBUTTONUP: | ||||
|             case WM_LBUTTONDBLCLK: | ||||
|             case WM_RBUTTONDOWN: | ||||
|             case WM_RBUTTONUP: | ||||
|             case WM_RBUTTONDBLCLK: | ||||
|             case WM_MBUTTONDOWN: | ||||
|             case WM_MBUTTONUP: | ||||
|             case WM_MBUTTONDBLCLK: | ||||
|  | ||||
|             case WM_SETFOCUS: | ||||
|             case WM_KILLFOCUS: | ||||
|                 wxCurrentPopupWindow->MSWDismissUnfocusedPopup(); | ||||
|         } | ||||
|     } | ||||
| #endif // wxUSE_POPUPWIN | ||||
|  | ||||
|     if ( !processed ) | ||||
|         return false; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user