From f3146210d7577355bc3d72a748ee830a1050d5ee Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 20 Aug 2008 16:07:06 +0000 Subject: [PATCH] MGR: async GUI RPCs: Create SafeMessageBox function to suspend periodic RPCs during modal dialogs svn path=/trunk/boinc/; revision=15901 --- checkin_notes | 26 +++++++++++++++++++++ clientgui/AccountInfoPage.cpp | 2 +- clientgui/AdvancedFrame.cpp | 2 +- clientgui/BOINCBaseFrame.cpp | 6 ++--- clientgui/BOINCDialupManager.cpp | 2 +- clientgui/BOINCGUIApp.cpp | 36 ++++++++++++++++++++++++++--- clientgui/BOINCGUIApp.h | 10 ++++++++ clientgui/BOINCTaskBar.cpp | 5 ++-- clientgui/DlgAdvPreferences.cpp | 4 ++-- clientgui/MainDocument.cpp | 15 ++++++++++++ clientgui/ValidateAccountKey.cpp | 3 ++- clientgui/ValidateEmailAddress.cpp | 3 ++- clientgui/ValidateURL.cpp | 3 ++- clientgui/ViewProjects.cpp | 4 ++-- clientgui/ViewTransfers.cpp | 2 +- clientgui/ViewWork.cpp | 4 ++-- clientgui/WizardAccountManager.cpp | 2 +- clientgui/WizardAttachProject.cpp | 2 +- clientgui/common/wxFlatNotebook.cpp | 2 +- clientgui/hyperlink.cpp | 2 +- clientgui/sg_StatImageLoader.cpp | 2 +- clientgui/sg_ViewTabPage.cpp | 2 +- 22 files changed, 111 insertions(+), 28 deletions(-) diff --git a/checkin_notes b/checkin_notes index e284e0f054..06719809d8 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6835,3 +6835,29 @@ Charlie 19 Aug 2008 samples/ mac_build/ UpperCase2.xcodeproj + +Charlie 20 Aug 2008 + - MGR: async GUI RPCs: Suspend periodic RPCs during modal dialogs. + + clientgui/ + AccountInfoPage.cpp + AdvancedFrame.cpp + BOINCBaseFrame.cpp,.h + BOINCDialupManager.cpp + BOINCGUIApp.cpp,.h + BOINCTaskBar.cpp + DlgAdvPreferences.cpp + hyperlink.cpp + MainDocument.cpp + sg_StatImageLoader.cpp + sg_ViewTabPage.cpp + ValidateAccountKey.cpp + ValidateEmailAddress.cpp + ValidateURL.cpp + ViewProjects.cpp + ViewTransfers.cpp + ViewWork.cpp + WizardAccountManager.cpp + WizardAttachProject.cpp + common/ + wxFlatNotebook.cpp diff --git a/clientgui/AccountInfoPage.cpp b/clientgui/AccountInfoPage.cpp index c4fde3bde8..b9a892259d 100644 --- a/clientgui/AccountInfoPage.cpp +++ b/clientgui/AccountInfoPage.cpp @@ -492,7 +492,7 @@ void CAccountInfoPage::OnPageChanging( wxWizardExEvent& event ) } if (bDisplayError) { - ::wxMessageBox( + wxGetApp().SafeMessageBox( strMessage, strTitle, wxICON_ERROR | wxOK, diff --git a/clientgui/AdvancedFrame.cpp b/clientgui/AdvancedFrame.cpp index c069201231..27c0bc2aa6 100644 --- a/clientgui/AdvancedFrame.cpp +++ b/clientgui/AdvancedFrame.cpp @@ -1365,7 +1365,7 @@ void CAdvancedFrame::OnAccountManagerDetach(wxCommandEvent& WXUNUSED(event)) { wxString(ami.acct_mgr_name.c_str(), wxConvUTF8).c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strMessage, strTitle, wxYES_NO | wxICON_QUESTION, diff --git a/clientgui/BOINCBaseFrame.cpp b/clientgui/BOINCBaseFrame.cpp index 27db17ea4d..913bc25ebb 100644 --- a/clientgui/BOINCBaseFrame.cpp +++ b/clientgui/BOINCBaseFrame.cpp @@ -240,7 +240,7 @@ void CBOINCBaseFrame::OnAlert(CFrameAlertEvent& event) { Show(); } - retval = ::wxMessageBox(event.m_message, event.m_title, event.m_style, this); + retval = SafeMessageBox(event.m_message, event.m_title, event.m_style, this); if (event.m_alert_event_type == AlertProcessResponse) { event.ProcessResponse(retval); } @@ -271,7 +271,7 @@ void CBOINCBaseFrame::OnAlert(CFrameAlertEvent& event) { ); } #elif defined (__WXMAC__) - // wxMessageBox() / ProcessResponse() hangs the Manager if hidden. + // SafeMessageBox() / ProcessResponse() hangs the Manager if hidden. // Currently, the only non-notification-only alert is Connection Failed, // which is now has logic to be displayed when Manager is maximized. @@ -282,7 +282,7 @@ void CBOINCBaseFrame::OnAlert(CFrameAlertEvent& event) { if (IsShown() && !event.m_notification_only) { int retval = 0; - retval = ::wxMessageBox(event.m_message, event.m_title, event.m_style, this); + retval = wxGetApp().SafeMessageBox(event.m_message, event.m_title, event.m_style, this); if (event.m_alert_event_type == AlertProcessResponse) { event.ProcessResponse(retval); } diff --git a/clientgui/BOINCDialupManager.cpp b/clientgui/BOINCDialupManager.cpp index b4485dd906..528199b33a 100644 --- a/clientgui/BOINCDialupManager.cpp +++ b/clientgui/BOINCDialupManager.cpp @@ -310,7 +310,7 @@ int CBOINCDialUpManager::Connect() { _("%s needs to connect to the Internet.\nMay it do so now?"), pSkinAdvanced->GetApplicationShortName().c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strDialogMessage, m_strDialogTitle, wxYES_NO | wxICON_QUESTION, diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index dd924cc9a7..78087c3224 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -92,6 +92,7 @@ bool CBOINCGUIApp::OnInit() { m_strDefaultDesktop = wxEmptyString; m_strDefaultDisplay = wxEmptyString; m_iGUISelected = BOINC_SIMPLEGUI; + m_bSafeMessageBoxDisplayed = 0; #ifdef __WXMSW__ m_hClientLibraryDll = NULL; #endif @@ -574,10 +575,9 @@ OSErr CBOINCGUIApp::QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEven FSSpec fileSpec; OSStatus anErr; - // Refuse to quit if a modal dialog is open. Search for the dialog - // by ID since all of BOINC Manager's dialog IDs are 10000. + // Refuse to quit if a modal dialog is open. // Unfortunately, I know of no way to disable the Quit item in our Dock menu - if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) { + if (wxGetApp().IsModalDialogDisplayed()) { SysBeep(4); return userCanceledErr; } @@ -833,4 +833,34 @@ int CBOINCGUIApp::ConfirmExit() { } +// Use this instead of wxMessageBox from all tab Views to suppress +// Periodic RPCs. See comment in CMainDocument::RunPeriodicRPCs() +// for a fuller explanation. +int CBOINCGUIApp::SafeMessageBox(const wxString& message, const wxString& caption, long style, + wxWindow *parent, int x, int y ) +{ + int retval; + + m_bSafeMessageBoxDisplayed++; + + retval = wxMessageBox(message, caption, style, parent, x, y); + + m_bSafeMessageBoxDisplayed--; + + return retval; +} + + +bool CBOINCGUIApp::IsModalDialogDisplayed() { + if (m_bSafeMessageBoxDisplayed) return true; + + // Search for the dialog by ID since all of BOINC Manager's + // dialog IDs are 10000. + if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) { + return true; + } + return false; +} + + const char *BOINC_RCSID_487cbf3018 = "$Id$"; diff --git a/clientgui/BOINCGUIApp.h b/clientgui/BOINCGUIApp.h index 21ea24cf9f..b900103b02 100644 --- a/clientgui/BOINCGUIApp.h +++ b/clientgui/BOINCGUIApp.h @@ -99,6 +99,8 @@ protected: // The last value defined in the wxLanguage enum is wxLANGUAGE_USER_DEFINED. // defined in: wx/intl.h wxArrayString m_astrLanguages; + + int m_bSafeMessageBoxDisplayed; public: @@ -142,6 +144,14 @@ public: int ConfirmExit(); + int SafeMessageBox(const wxString& message, + const wxString& caption = wxMessageBoxCaptionStr, + long style = wxOK | wxCENTRE, + wxWindow *parent = NULL, + int x = wxDefaultCoord, int y = wxDefaultCoord); + + bool IsModalDialogDisplayed(); + DECLARE_EVENT_TABLE() }; diff --git a/clientgui/BOINCTaskBar.cpp b/clientgui/BOINCTaskBar.cpp index 2079e36a0e..18c660dba7 100644 --- a/clientgui/BOINCTaskBar.cpp +++ b/clientgui/BOINCTaskBar.cpp @@ -633,13 +633,12 @@ void CTaskBarIcon::AdjustMenuItems(wxMenu* pMenu) { // BOINC Manager crashes if user selects "Exit" from taskbar menu while // a dialog is open, so we must disable the "Exit" menu item if a dialog - // is open. So lets search for the dialog by ID since all of BOINC - // Manager's dialog IDs are 10000. + // is open. // On the Mac, the user can open multiple instances of the About dialog // by repeatedly selecting "About" menu item from the taskbar, so we // must also disable that item. For consistency with the Mac standard, // we disable the entire taskbar menu when a modal dialog is open. - if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) { + if (wxGetApp().IsModalDialogDisplayed()) { is_dialog_detected = true; } diff --git a/clientgui/DlgAdvPreferences.cpp b/clientgui/DlgAdvPreferences.cpp index ddcc108274..1c9ccc414b 100644 --- a/clientgui/DlgAdvPreferences.cpp +++ b/clientgui/DlgAdvPreferences.cpp @@ -572,7 +572,7 @@ void CDlgAdvPreferences::ShowErrorMessage(wxString& message,wxTextCtrl* errorCtr if(message.IsEmpty()){ message = _("invalid input value detected"); } - wxMessageBox(message,_("Validation Error"),wxOK | wxCENTRE | wxICON_ERROR,this); + wxGetApp().SafeMessageBox(message,_("Validation Error"),wxOK | wxCENTRE | wxICON_ERROR,this); } /* checks if ch is a valid character for float values */ @@ -706,7 +706,7 @@ void CDlgAdvPreferences::OnClear(wxCommandEvent& ev) { } bool CDlgAdvPreferences::ConfirmClear() { - int res = wxMessageBox(_("Do you really want to clear all local preferences ?"), + int res = wxGetApp().SafeMessageBox(_("Do you really want to clear all local preferences ?"), _("Confirmation"),wxCENTER | wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT,this); return res==wxYES; diff --git a/clientgui/MainDocument.cpp b/clientgui/MainDocument.cpp index e29d07fe0e..84082d552b 100644 --- a/clientgui/MainDocument.cpp +++ b/clientgui/MainDocument.cpp @@ -31,6 +31,7 @@ #include "BOINCBaseFrame.h" #include "MainDocument.h" #include "BOINCClientManager.h" +#include "Events.h" #ifndef _WIN32 #include @@ -731,6 +732,20 @@ void CMainDocument::RunPeriodicRPCs() { // TODO: modify SimpleGUI to not do RPCs when hidden / minimized if (! ((currentTabView & VW_SGUI) || pFrame->IsShown()) ) return; + // several functions (such as Abort, Reset, Detach) display an + // "Are you sure?" dialog before passing a pointer to a result + // or project in a demand RPC call. If Periodic RPCs continue + // to run during these dialogs, that pointer may no longer be + // valid by the time the demand RPC is executed. So we suspend + // periodic RPCs during modal dialogs. Search for the dialog + // by ID since all of BOINC Manager's dialog IDs are 10000. + // + // Note that this depends on using wxGetApp().SafeMessageBox() + // instead of wxMessageBox in all tab views. + if (wxGetApp().IsModalDialogDisplayed()) { + return; + } + wxDateTime dtNow(wxDateTime::Now()); // *********** RPC_GET_CC_STATUS ************** diff --git a/clientgui/ValidateAccountKey.cpp b/clientgui/ValidateAccountKey.cpp index 87e83f870a..70fd006e08 100644 --- a/clientgui/ValidateAccountKey.cpp +++ b/clientgui/ValidateAccountKey.cpp @@ -21,6 +21,7 @@ #include "stdwx.h" #include "ValidateAccountKey.h" +#include "BOINCGUIApp.h" IMPLEMENT_DYNAMIC_CLASS(CValidateAccountKey, wxValidator) @@ -78,7 +79,7 @@ bool CValidateAccountKey::Validate(wxWindow *parent) { wxString buf; buf.Printf(m_errormsg, control->GetValue().c_str()); - wxMessageBox(buf, _("Validation conflict"), + wxGetApp().SafeMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent ); } diff --git a/clientgui/ValidateEmailAddress.cpp b/clientgui/ValidateEmailAddress.cpp index 40bca5c366..70504716e6 100644 --- a/clientgui/ValidateEmailAddress.cpp +++ b/clientgui/ValidateEmailAddress.cpp @@ -21,6 +21,7 @@ #include "stdwx.h" #include "ValidateEmailAddress.h" +#include "BOINCGUIApp.h" IMPLEMENT_DYNAMIC_CLASS(CValidateEmailAddress, wxValidator) @@ -82,7 +83,7 @@ bool CValidateEmailAddress::Validate(wxWindow *parent) { wxString buf; buf.Printf(m_errormsg, control->GetValue().c_str()); - wxMessageBox(buf, _("Validation conflict"), + wxGetApp().SafeMessageBox(buf, _("Validation conflict"), wxOK | wxICON_EXCLAMATION, parent ); } diff --git a/clientgui/ValidateURL.cpp b/clientgui/ValidateURL.cpp index c4320de08f..ecb32770bc 100644 --- a/clientgui/ValidateURL.cpp +++ b/clientgui/ValidateURL.cpp @@ -21,6 +21,7 @@ #include "stdwx.h" #include "ValidateURL.h" +#include "BOINCGUIApp.h" #include "str_util.h" @@ -121,7 +122,7 @@ bool CValidateURL::Validate(wxWindow *parent) { wxString buf; buf.Printf(m_errormsg, control->GetValue().c_str()); - wxMessageBox(buf, m_errortitle, + wxGetApp().SafeMessageBox(buf, m_errortitle, wxOK | wxICON_EXCLAMATION, parent ); } diff --git a/clientgui/ViewProjects.cpp b/clientgui/ViewProjects.cpp index e89e4fceaa..48c4b8830f 100644 --- a/clientgui/ViewProjects.cpp +++ b/clientgui/ViewProjects.cpp @@ -392,7 +392,7 @@ void CViewProjects::OnProjectReset( wxCommandEvent& WXUNUSED(event) ) { pProject->m_strProjectName.c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strMessage, _("Reset Project"), wxYES_NO | wxICON_QUESTION, @@ -447,7 +447,7 @@ void CViewProjects::OnProjectDetach( wxCommandEvent& WXUNUSED(event) ) { pProject->m_strProjectName.c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strMessage, _("Detach from Project"), wxYES_NO | wxICON_QUESTION, diff --git a/clientgui/ViewTransfers.cpp b/clientgui/ViewTransfers.cpp index 765128798d..085664d9f1 100644 --- a/clientgui/ViewTransfers.cpp +++ b/clientgui/ViewTransfers.cpp @@ -271,7 +271,7 @@ void CViewTransfers::OnTransfersAbort( wxCommandEvent& WXUNUSED(event) ) { pTransfer->m_strFileName.c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strMessage, _("Abort File Transfer"), wxYES_NO | wxICON_QUESTION, diff --git a/clientgui/ViewWork.cpp b/clientgui/ViewWork.cpp index 5ebda604eb..0f3f52cc75 100644 --- a/clientgui/ViewWork.cpp +++ b/clientgui/ViewWork.cpp @@ -297,7 +297,7 @@ void CViewWork::OnWorkShowGraphics( wxCommandEvent& WXUNUSED(event) ) { #if (defined(_WIN32) || defined(__WXMAC__)) pDoc->GetConnectedComputerName(strMachineName); if (!pDoc->IsComputerNameLocal(strMachineName)) { - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( _("Are you sure you want to display graphics on a remote machine?"), _("Show graphics"), wxYES_NO | wxICON_QUESTION, @@ -375,7 +375,7 @@ void CViewWork::OnWorkAbort( wxCommandEvent& WXUNUSED(event) ) { strStatus.c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strMessage, _("Abort task"), wxYES_NO | wxICON_QUESTION, diff --git a/clientgui/WizardAccountManager.cpp b/clientgui/WizardAccountManager.cpp index a31d2a2a70..b58101a645 100644 --- a/clientgui/WizardAccountManager.cpp +++ b/clientgui/WizardAccountManager.cpp @@ -430,7 +430,7 @@ void CWizardAccountManager::_ProcessCancelEvent( wxWizardExEvent& event ) { bool bCancelWithoutNextPage = false; wxWizardPageEx* page = GetCurrentPage(); - int iRetVal = ::wxMessageBox( + int iRetVal = wxGetApp().SafeMessageBox( _("Do you really want to cancel?"), _("Question"), wxICON_QUESTION | wxYES_NO, diff --git a/clientgui/WizardAttachProject.cpp b/clientgui/WizardAttachProject.cpp index f519ec75a0..5bdffe9d02 100644 --- a/clientgui/WizardAttachProject.cpp +++ b/clientgui/WizardAttachProject.cpp @@ -462,7 +462,7 @@ void CWizardAttachProject::_ProcessCancelEvent( wxWizardExEvent& event ) { bool bCancelWithoutNextPage = false; wxWizardPageEx* page = GetCurrentPage(); - int iRetVal = ::wxMessageBox( + int iRetVal = wxGetApp().SafeMessageBox( _("Do you really want to cancel?"), _("Question"), wxICON_QUESTION | wxYES_NO, diff --git a/clientgui/common/wxFlatNotebook.cpp b/clientgui/common/wxFlatNotebook.cpp index c176f3432b..08b9ee3f1a 100644 --- a/clientgui/common/wxFlatNotebook.cpp +++ b/clientgui/common/wxFlatNotebook.cpp @@ -1390,7 +1390,7 @@ int wxPageContainerBase::HitTest(const wxPoint& pt, wxPageInfo& pageInfo, int &t if(tabRect.Inside(pt)) { // We have a match - // wxMessageBox(pgInfo.m_strCaption); + // wxGetApp().SafeMessageBox(pgInfo.m_strCaption); pageInfo = pgInfo; tabIdx = (int)cur; return wxFNB_TAB; diff --git a/clientgui/hyperlink.cpp b/clientgui/hyperlink.cpp index 8ea949ebf8..6d7b730a6a 100644 --- a/clientgui/hyperlink.cpp +++ b/clientgui/hyperlink.cpp @@ -195,7 +195,7 @@ void wxHyperLink::ExecuteLink (const wxString &strLink) { wxGetApp().GetSkinManager()->GetAdvanced()->GetApplicationName().c_str() ); - ::wxMessageBox( + ::wxGetApp().SafeMessageBox( strDialogMessage, strDialogTitle, wxOK | wxICON_INFORMATION diff --git a/clientgui/sg_StatImageLoader.cpp b/clientgui/sg_StatImageLoader.cpp index 9766f743f2..b1ee063b3e 100644 --- a/clientgui/sg_StatImageLoader.cpp +++ b/clientgui/sg_StatImageLoader.cpp @@ -217,7 +217,7 @@ void StatImageLoader::OnProjectDetach() { strProjectName.c_str() ); - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( strMessage, _("Detach from Project"), wxYES_NO | wxICON_QUESTION, diff --git a/clientgui/sg_ViewTabPage.cpp b/clientgui/sg_ViewTabPage.cpp index d244f488ea..28bbe0fad2 100644 --- a/clientgui/sg_ViewTabPage.cpp +++ b/clientgui/sg_ViewTabPage.cpp @@ -413,7 +413,7 @@ void CViewTabPage::OnWorkShowGraphics() { #if (defined(_WIN32) || defined(__WXMAC__)) pDoc->GetConnectedComputerName(strMachineName); if (!pDoc->IsComputerNameLocal(strMachineName)) { - iAnswer = ::wxMessageBox( + iAnswer = wxGetApp().SafeMessageBox( _("Are you sure you want to display graphics on a remote machine?"), _("Show graphics"), wxYES_NO | wxICON_QUESTION,