From e6607a63402a2b4ce2d88588efa2c011ffae9b86 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Fri, 16 Jan 2015 03:22:10 -0800 Subject: [PATCH] MGR: work around a Linux bug in wxWidgets which prevents bringing the main window forward on top of Event Log (or any modeless dialog.) - On all platforms, preserve Z-order of main window and Event Log when hiding / showing or deactivating / activating Manager. --- clientgui/BOINCBaseFrame.cpp | 9 ++++- clientgui/BOINCBaseFrame.h | 1 + clientgui/BOINCGUIApp.cpp | 65 ++++++++++++++++++++---------------- clientgui/BOINCGUIApp.h | 3 ++ clientgui/DlgEventLog.cpp | 17 ++++++++-- clientgui/DlgEventLog.h | 14 +++++++- 6 files changed, 76 insertions(+), 33 deletions(-) diff --git a/clientgui/BOINCBaseFrame.cpp b/clientgui/BOINCBaseFrame.cpp index ae2b9ae556..14d5bc7881 100644 --- a/clientgui/BOINCBaseFrame.cpp +++ b/clientgui/BOINCBaseFrame.cpp @@ -56,6 +56,7 @@ BEGIN_EVENT_TABLE (CBOINCBaseFrame, wxFrame) EVT_FRAME_INITIALIZED(CBOINCBaseFrame::OnInitialized) EVT_FRAME_ALERT(CBOINCBaseFrame::OnAlert) EVT_FRAME_REFRESH(CBOINCBaseFrame::OnRefreshView) + EVT_ACTIVATE(CBOINCBaseFrame::OnActivate) EVT_CLOSE(CBOINCBaseFrame::OnClose) EVT_MENU(ID_CLOSEWINDOW, CBOINCBaseFrame::OnCloseWindow) EVT_MENU(wxID_EXIT, CBOINCBaseFrame::OnExit) @@ -314,6 +315,13 @@ void CBOINCBaseFrame::OnAlert(CFrameAlertEvent& event) { } +void CBOINCBaseFrame::OnActivate(wxActivateEvent& event) { + bool isActive = event.GetActive(); + if (isActive) wxGetApp().SetEventLogWasActive(false); + event.Skip(); +} + + void CBOINCBaseFrame::OnClose(wxCloseEvent& event) { wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseFrame::OnClose - Function Begin")); @@ -888,7 +896,6 @@ bool CBOINCBaseFrame::Show(bool bShow) { #else retval = wxFrame::Show(bShow); #endif - if (bShow) wxFrame::Raise(); wxLogTrace(wxT("Function Start/End"), wxT("CBOINCBaseFrame::Show - Function End")); return retval; diff --git a/clientgui/BOINCBaseFrame.h b/clientgui/BOINCBaseFrame.h index abc3694f2a..3e226bf2f6 100644 --- a/clientgui/BOINCBaseFrame.h +++ b/clientgui/BOINCBaseFrame.h @@ -59,6 +59,7 @@ public: void OnInitialized( CFrameEvent& event ); virtual void OnAlert( CFrameAlertEvent& event ); + virtual void OnActivate( wxActivateEvent& event ); virtual void OnClose( wxCloseEvent& event ); virtual void OnCloseWindow( wxCommandEvent& event ); virtual void OnExit( wxCommandEvent& event ); diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index 31dc7a617f..11c22862cb 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -370,6 +370,8 @@ bool CBOINCGUIApp::OnInit() { m_pDocument = NULL; m_pTaskBarIcon = NULL; m_pEventLog = NULL; + m_bEventLogWasActive = false; + m_bProcessingActivateAppEvent = false; #ifdef __WXMAC__ m_pMacDockIcon = NULL; #endif @@ -1191,26 +1193,28 @@ int CBOINCGUIApp::IdleTrackerDetach() { void CBOINCGUIApp::OnActivateApp(wxActivateEvent& event) { -#ifdef __WXMAC__ - // Make sure any modal dialog (such as Attach Wizard) ends up in front. - if (IsModalDialogDisplayed()) { - event.Skip(); - return; - } -#endif + m_bProcessingActivateAppEvent = true; if (event.GetActive()) { - if (m_pEventLog && !m_pEventLog->IsIconized()) { +#ifdef __WXMAC__ + ShowInterface(); +#else + bool keepEventLogInFront = m_bEventLogWasActive; + + if (m_pEventLog && !m_pEventLog->IsIconized() && !keepEventLogInFront) { m_pEventLog->Raise(); } if (m_pFrame) { m_pFrame->Raise(); } -#ifdef __WXMAC__ - ShowInterface(); + if (m_pEventLog && !m_pEventLog->IsIconized() && keepEventLogInFront) { + m_pEventLog->Raise(); + } #endif } event.Skip(); + + m_bProcessingActivateAppEvent = false; } @@ -1263,8 +1267,11 @@ int CBOINCGUIApp::StartBOINCDefaultScreensaverTest() { } -// Display the Event Log, it is a modeless dialog not owned by any -// other UI element. +// Display the Event Log, it is a modeless dialog not owned by +// any other UI element. +// To work around a Linux bug in wxWidgets 3.0 which prevents +// bringing the main frame forward on top of a modeless dialog, +// the Event Log is now a wxFrame on Linux only. void CBOINCGUIApp::DisplayEventLog(bool bShowWindow) { if (m_pEventLog) { if (bShowWindow) { @@ -1422,26 +1429,28 @@ bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) { } // Show the new frame if needed - if (m_pFrame && bShowWindow) { - if (m_pEventLog) { - m_pEventLog->Show(); - m_pEventLog->Raise(); -#ifdef __WXMSW__ - ::SetForegroundWindow((HWND)m_pEventLog->GetHWND()); -#endif - } + if (!m_bProcessingActivateAppEvent) { + if (m_pFrame && bShowWindow) { + if (m_pEventLog && !m_pEventLog->IsIconized()) { + m_pEventLog->Show(); + m_pEventLog->Raise(); + #ifdef __WXMSW__ + ::SetForegroundWindow((HWND)m_pEventLog->GetHWND()); + #endif + } - if (!m_pFrame->IsShown()) { - m_pFrame->Show(); - } - if (m_pFrame->IsIconized()) { - m_pFrame->Maximize(false); - } - m_pFrame->Raise(); + if (!m_pFrame->IsShown()) { + m_pFrame->Show(); + } + if (m_pFrame->IsIconized()) { + m_pFrame->Maximize(false); + } + m_pFrame->Raise(); #ifdef __WXMSW__ - ::SetForegroundWindow((HWND)m_pFrame->GetHWND()); + ::SetForegroundWindow((HWND)m_pFrame->GetHWND()); #endif + } } wxLogTrace(wxT("Function Start/End"), wxT("CBOINCGUIApp::SetActiveGUI - Function End")); diff --git a/clientgui/BOINCGUIApp.h b/clientgui/BOINCGUIApp.h index 6990d9d7a3..ec1a8b046e 100644 --- a/clientgui/BOINCGUIApp.h +++ b/clientgui/BOINCGUIApp.h @@ -79,6 +79,8 @@ protected: CMainDocument* m_pDocument; CTaskBarIcon* m_pTaskBarIcon; CDlgEventLog* m_pEventLog; + bool m_bEventLogWasActive; + bool m_bProcessingActivateAppEvent; #ifdef __WXMAC__ CTaskBarIcon* m_pMacDockIcon; #endif @@ -161,6 +163,7 @@ public: void SetISOLanguageCode(wxString strISOLanguageCode) { m_strISOLanguageCode = strISOLanguageCode; } + void SetEventLogWasActive(bool wasActive) { m_bEventLogWasActive = wasActive; } void DisplayEventLog(bool bShowWindow = true); void OnEventLogClose(); diff --git a/clientgui/DlgEventLog.cpp b/clientgui/DlgEventLog.cpp index 79feef7ba0..5cc7df16d3 100644 --- a/clientgui/DlgEventLog.cpp +++ b/clientgui/DlgEventLog.cpp @@ -66,14 +66,15 @@ static std::string s_strFilteredProjectName; * CDlgEventLog type definition */ -IMPLEMENT_DYNAMIC_CLASS( CDlgEventLog, wxDialog ) +IMPLEMENT_DYNAMIC_CLASS( CDlgEventLog, DlgEventLogBase ) /*! * CDlgEventLog event table definition */ -BEGIN_EVENT_TABLE( CDlgEventLog, wxDialog ) +BEGIN_EVENT_TABLE( CDlgEventLog, DlgEventLogBase ) ////@begin CDlgEventLog event table entries + EVT_ACTIVATE(CDlgEventLog::OnActivate) EVT_HELP(wxID_ANY, CDlgEventLog::OnHelp) EVT_BUTTON(wxID_OK, CDlgEventLog::OnOK) EVT_BUTTON(ID_COPYAll, CDlgEventLog::OnMessagesCopyAll) @@ -215,7 +216,7 @@ bool CDlgEventLog::Create( wxWindow* parent, wxWindowID id, const wxString& capt oTempSize = size; } - wxDialog::Create( parent, id, caption, oTempPoint, oTempSize, style ); + DlgEventLogBase::Create( parent, id, caption, oTempPoint, oTempSize, style ); SetSizeHints(DLGEVENTLOG_MIN_WIDTH, DLGEVENTLOG_MIN_HEIGHT); SetExtraStyle(GetExtraStyle()|wxWS_EX_BLOCK_EVENTS); @@ -394,6 +395,16 @@ void CDlgEventLog::SetTextColor() { } +/*! + * wxEVT_ACTIVATE event handler for ID_DLGMESSAGES + */ + +void CDlgEventLog::OnActivate(wxActivateEvent& event) { + bool isActive = event.GetActive(); + if (isActive) wxGetApp().SetEventLogWasActive(true); + event.Skip(); +} + /*! * wxEVT_HELP event handler for ID_DLGMESSAGES */ diff --git a/clientgui/DlgEventLog.h b/clientgui/DlgEventLog.h index e429b7413a..e53e9f63f7 100644 --- a/clientgui/DlgEventLog.h +++ b/clientgui/DlgEventLog.h @@ -74,7 +74,16 @@ class CDlgEventLogListCtrl; #define wxFIXED_MINSIZE 0 #endif -class CDlgEventLog : public wxDialog +// To work around a Linux bug in wxWidgets 3.0 which prevents +// bringing the main frame forward on top of a modeless dialog, +// the Event Log is now a wxFrame on Linux only. +#ifdef __WXGTK__ +#define DlgEventLogBase wxFrame +#else +#define DlgEventLogBase wxDialog +#endif + +class CDlgEventLog : public DlgEventLogBase { DECLARE_DYNAMIC_CLASS( CDlgEventLog ) DECLARE_EVENT_TABLE() @@ -100,6 +109,9 @@ public: /// wxEVT_HELP event handler for ID_DLGEVENTLOG void OnHelp( wxHelpEvent& event ); + /// wxEVT_Activate event handler for ID_DLGEVENTLOG + void OnActivate( wxActivateEvent& event ); + /// wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK void OnOK( wxCommandEvent& event );