diff --git a/checkin_notes b/checkin_notes index 97f76b673a..8261700acd 100755 --- a/checkin_notes +++ b/checkin_notes @@ -12091,3 +12091,18 @@ Rom 3 Nov 2006 boinc_cmd.C gui_rpc_client.h gui_rpc_client_ops.C + +Charlie 3 Nov 2006 + - Mac: Rework Exit Confirmation logic so dialog is presented when + user exits Manager from system tray icon or any other means. + Rewrote dialog text to be more clear, and changed it back to a + fixed string because strings read in from skins.xml file are + not easily localized. The project and application names are + still read from skins.xml and inserted in dialog text. + + clientgui/ + AdvancedFrame.cpp, h + BOINCBaseFrame.cpp, h + BOINCGUIApp.cpp, h + BOINCTaskBar.cpp + sg_BoincSimpleGUI.cpp diff --git a/clientgui/AdvancedFrame.cpp b/clientgui/AdvancedFrame.cpp index c297b4b6b2..fead987e61 100644 --- a/clientgui/AdvancedFrame.cpp +++ b/clientgui/AdvancedFrame.cpp @@ -47,7 +47,6 @@ #include "ViewStatistics.h" #include "ViewResources.h" #include "DlgAbout.h" -#include "DlgGenericMessage.h" #include "DlgOptions.h" #include "DlgSelectComputer.h" #include "wizardex.h" @@ -549,7 +548,7 @@ bool CAdvancedFrame::CreateMenu() { MenuRef prefsMenuRef; MenuItemIndex prefsMenuItemIndex; - // Hide Mac OS X's standard Preferences menu ite, since we don't use it + // Hide Mac OS X's standard Preferences menu item, since we don't use it if (GetIndMenuItemWithCommandID(NULL, kHICommandPreferences, 1, &prefsMenuRef, &prefsMenuItemIndex) == noErr) ChangeMenuItemAttributes(prefsMenuRef, prefsMenuItemIndex, kMenuItemAttrHidden, 0); #endif @@ -1077,45 +1076,6 @@ void CAdvancedFrame::OnCloseWindow(wxCommandEvent& WXUNUSED(event)) { #endif -void CAdvancedFrame::OnExit(wxCommandEvent& WXUNUSED(event)) { - wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::OnExit - Function Begin")); - -#ifdef __WXMAC__ - // Don't run confirmation dialog if logging out or shutting down - if (wxGetApp().GetQuittingByAppleEvent()) { - Close(true); - return; - } -#endif - - if (m_iDisplayExitWarning) { - CDlgGenericMessage* pDlg = new CDlgGenericMessage(this); - wxString strMessage = wxGetApp().GetSkinManager()->GetAdvanced()->GetExitMessage(); - long lAnswer = 0; - - pDlg->SetTitle(_("Close Confirmation")); - pDlg->m_DialogMessage->SetLabel(strMessage); - pDlg->Fit(); - pDlg->Centre(); - - lAnswer = pDlg->ShowModal(); - if (wxID_OK == lAnswer) { - if (pDlg->m_DialogDisableMessage->GetValue()) { - m_iDisplayExitWarning = 0; - } - Close(true); - } - - if (pDlg) - pDlg->Destroy(); - - } else { - Close(true); - } - - wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::OnExit - Function End")); -} - void CAdvancedFrame::OnProjectsAttachToAccountManager(wxCommandEvent& WXUNUSED(event)) { wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::OnProjectsAttachToAccountManager - Function Begin")); diff --git a/clientgui/AdvancedFrame.h b/clientgui/AdvancedFrame.h index 92c9473e7c..2b8efcaf85 100644 --- a/clientgui/AdvancedFrame.h +++ b/clientgui/AdvancedFrame.h @@ -64,7 +64,6 @@ public: #ifdef __WXMAC__ void OnCloseWindow( wxCommandEvent& event ); #endif - void OnExit( wxCommandEvent& event ); void OnCommandsRetryCommunications( wxCommandEvent& event ); diff --git a/clientgui/BOINCBaseFrame.cpp b/clientgui/BOINCBaseFrame.cpp index cab0b6ac76..7bf3a5515f 100644 --- a/clientgui/BOINCBaseFrame.cpp +++ b/clientgui/BOINCBaseFrame.cpp @@ -72,7 +72,7 @@ CBOINCBaseFrame::CBOINCBaseFrame(wxWindow* parent, const wxWindowID id, const wx // Configuration Settings m_iSelectedLanguage = 0; m_iReminderFrequency = 0; - m_iDisplayExitWarning = 1; + wxGetApp().SetDisplayExitWarning(1); m_strNetworkDialupConnectionName = wxEmptyString; @@ -285,6 +285,16 @@ void CBOINCBaseFrame::OnClose(wxCloseEvent& event) { } +void CBOINCBaseFrame::OnExit(wxCommandEvent& WXUNUSED(event)) { + wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::OnExit - Function Begin")); + + if (wxGetApp().ConfirmExit()) + Close(true); + + wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::OnExit - Function End")); +} + + void CBOINCBaseFrame::FireInitialize() { CFrameEvent event(wxEVT_FRAME_INITIALIZED, this); AddPendingEvent(event); @@ -466,7 +476,7 @@ bool CBOINCBaseFrame::SaveState() { pConfig->Write(wxT("Language"), m_iSelectedLanguage); pConfig->Write(wxT("ReminderFrequency"), m_iReminderFrequency); - pConfig->Write(wxT("DisplayExitWarning"), m_iDisplayExitWarning); + pConfig->Write(wxT("DisplayExitWarning"), wxGetApp().GetDisplayExitWarning()); pConfig->Write(wxT("NetworkDialupConnectionName"), m_strNetworkDialupConnectionName); @@ -507,6 +517,7 @@ bool CBOINCBaseFrame::RestoreState() { wxString strValue; long iIndex; bool bKeepEnumerating = false; + int iDisplayExitWarning; wxASSERT(pConfig); @@ -524,7 +535,8 @@ bool CBOINCBaseFrame::RestoreState() { pConfig->Read(wxT("Language"), &m_iSelectedLanguage, 0L); pConfig->Read(wxT("ReminderFrequency"), &m_iReminderFrequency, 60L); - pConfig->Read(wxT("DisplayExitWarning"), &m_iDisplayExitWarning, 1L); + pConfig->Read(wxT("DisplayExitWarning"), &iDisplayExitWarning, 1L); + wxGetApp().SetDisplayExitWarning(iDisplayExitWarning); pConfig->Read(wxT("NetworkDialupConnectionName"), &m_strNetworkDialupConnectionName, wxEmptyString); diff --git a/clientgui/BOINCBaseFrame.h b/clientgui/BOINCBaseFrame.h index 143db914d8..3146c24ddc 100644 --- a/clientgui/BOINCBaseFrame.h +++ b/clientgui/BOINCBaseFrame.h @@ -59,7 +59,8 @@ public: virtual void OnAlert( CFrameAlertEvent& event ); virtual void OnClose( wxCloseEvent& event ); - + void OnExit( wxCommandEvent& event ); + int GetReminderFrequency() { return m_iReminderFrequency; } wxString GetDialupConnectionName() { return m_strNetworkDialupConnectionName; } @@ -96,7 +97,6 @@ protected: int m_iSelectedLanguage; int m_iReminderFrequency; - int m_iDisplayExitWarning; wxString m_strNetworkDialupConnectionName; diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index 6ac5e81247..d88c033992 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -45,6 +45,7 @@ #include "BOINCTaskBar.h" #include "BOINCBaseFrame.h" #include "AdvancedFrame.h" +#include "DlgGenericMessage.h" #ifdef SIMPLEGUI @@ -55,7 +56,7 @@ #include "sg_BoincSimpleGUI.h" #endif -static bool s_bQuittingByAppleEvent; +static bool s_bSkipExitConfirmation; #ifdef __WXMSW__ EXTERN_C BOOL IsBOINCServiceInstalled(); @@ -298,7 +299,7 @@ bool CBOINCGUIApp::OnInit() { StartupBOINCCore(); #ifdef __WXMAC__ - s_bQuittingByAppleEvent = false; + s_bSkipExitConfirmation = false; AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false ); m_pMacSystemMenu = new CMacSystemMenu( @@ -796,13 +797,44 @@ void CBOINCGUIApp::ShutdownBOINCCore() { } +// Set s_bSkipExitConfirmation to true if cancelled because of logging out or shutting down OSErr CBOINCGUIApp::QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) { - s_bQuittingByAppleEvent = true; - return wxGetApp().MacHandleAEQuit((AppleEvent*)appleEvt, reply); -} + DescType senderType; + Size actualSize; + ProcessSerialNumber SenderPSN, ourPSN; + Boolean isSame; + ProcessInfoRec pInfo; + FSSpec fileSpec; + OSStatus anErr; -bool CBOINCGUIApp::GetQuittingByAppleEvent() { - return s_bQuittingByAppleEvent; + anErr = AEGetAttributePtr(appleEvt, keyAddressAttr, typeProcessSerialNumber, + &senderType, &SenderPSN, sizeof(SenderPSN), &actualSize); + + if (anErr == noErr) { + + GetCurrentProcess(&ourPSN); + + anErr = SameProcess(&SenderPSN, &ourPSN, &isSame); + + if (anErr == noErr) { + if (!isSame) { + + pInfo.processInfoLength = sizeof( ProcessInfoRec ); + pInfo.processName = NULL; + pInfo.processAppSpec = &fileSpec; + + anErr = GetProcessInformation(&SenderPSN, &pInfo); + + // Consider a Quit command from our Dock menu as coming from this application + if (pInfo.processSignature != 'dock') { + s_bSkipExitConfirmation = true; // Not from our app, our dock icon or our taskbar icon + wxGetApp().ExitMainLoop(); // Prevents wxMac from issuing events to closed frames + } + } + } + } + + return wxGetApp().MacHandleAEQuit((AppleEvent*)appleEvt, reply); } #else @@ -991,4 +1023,61 @@ bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) { } +int CBOINCGUIApp::ConfirmExit() { + if (! m_bBOINCStartedByManager) + return 1; // Don't run dialog if exiting manager won't shut down Client or its tasks + + if (! m_iDisplayExitWarning) + return 1; + +#ifdef __WXMAC__ + // Don't run confirmation dialog if logging out or shutting down + if (s_bSkipExitConfirmation) + return 1; + + ProcessSerialNumber psn; + + GetCurrentProcess(&psn); + SetFrontProcess(&psn); // Shows process if hidden +#endif + + CDlgGenericMessage* pDlg = new CDlgGenericMessage(NULL); + wxString strBaseMessage = _("This will shut down %s and its tasks entirely until either the\n" + "%s application or the %s screen saver is run again.\n\n" + "In most cases, it is better just to close the %s window\n" + "rather than to exit the application; that will allow %s to run its\n" + "tasks at the times you selected in your preferences."); + long lAnswer = 0; + char msgBuf[1024]; + + const char *appName = m_pSkinManager->GetAdvanced()->GetApplicationName().c_str(); + const char *projName = m_pSkinManager->GetAdvanced()->GetProjectName().c_str(); + + if (strlen(appName) > 100) // Safety tests to prevent buffer overrun + appName = "BOINC Manager"; + if (strlen(projName) > 100) + projName = "BOINC"; + + sprintf(msgBuf, strBaseMessage.c_str(), projName, appName, projName, appName, projName); + wxString strFullMessage = wxString(msgBuf); + + pDlg->SetTitle(_("Exit Confirmation")); + pDlg->m_DialogMessage->SetLabel(strFullMessage); + pDlg->Fit(); + pDlg->Centre(); + + lAnswer = pDlg->ShowModal(); + if (pDlg) { + pDlg->Destroy(); + if (wxID_OK == lAnswer) { + if (pDlg->m_DialogDisableMessage->GetValue()) { + m_iDisplayExitWarning = 0; + } + return 1; + } + } + return 0; // User cancelled exit +} + + const char *BOINC_RCSID_487cbf3018 = "$Id$"; diff --git a/clientgui/BOINCGUIApp.h b/clientgui/BOINCGUIApp.h index 8c5cf822ae..44c1ebe46b 100644 --- a/clientgui/BOINCGUIApp.h +++ b/clientgui/BOINCGUIApp.h @@ -76,6 +76,7 @@ protected: #endif bool m_bBOINCStartedByManager; + int m_iDisplayExitWarning; bool m_bGUIVisible; int m_iGUISelected; @@ -115,14 +116,18 @@ public: #ifdef __WXMAC__ CMacSystemMenu* GetMacSystemMenu() { return m_pMacSystemMenu; } int GetCurrentGUISelection() { return m_iGUISelected; } - bool GetQuittingByAppleEvent(); #endif wxArrayString& GetSupportedLanguages() { return m_astrLanguages; } + int GetDisplayExitWarning() { return m_iDisplayExitWarning; } + void SetDisplayExitWarning(int display) { m_iDisplayExitWarning = display; } + void FireReloadSkin(); bool SetActiveGUI(int iGUISelection, bool bShowWindow = true); + + int ConfirmExit(); }; diff --git a/clientgui/BOINCTaskBar.cpp b/clientgui/BOINCTaskBar.cpp index 18b2c4b8ff..c0e970626e 100644 --- a/clientgui/BOINCTaskBar.cpp +++ b/clientgui/BOINCTaskBar.cpp @@ -311,10 +311,12 @@ void CTaskBarIcon::OnAbout(wxCommandEvent& WXUNUSED(event)) { void CTaskBarIcon::OnExit(wxCommandEvent& event) { wxLogTrace(wxT("Function Start/End"), wxT("CTaskBarIcon::OnExit - Function Begin")); - wxCloseEvent eventClose; - OnClose(eventClose); - if (eventClose.GetSkipped()) event.Skip(); - + if (wxGetApp().ConfirmExit()) { + wxCloseEvent eventClose; + OnClose(eventClose); + if (eventClose.GetSkipped()) event.Skip(); + } + wxLogTrace(wxT("Function Start/End"), wxT("CTaskBarIcon::OnExit - Function End")); } diff --git a/clientgui/sg_BoincSimpleGUI.cpp b/clientgui/sg_BoincSimpleGUI.cpp index 8163bc1cfd..a7145119a6 100644 --- a/clientgui/sg_BoincSimpleGUI.cpp +++ b/clientgui/sg_BoincSimpleGUI.cpp @@ -58,6 +58,7 @@ BEGIN_EVENT_TABLE(CSimpleFrame, CBOINCBaseFrame) #ifndef __WXMAC__ EVT_ERASE_BACKGROUND(CSimpleFrame::OnEraseBackground) #endif + EVT_MENU(wxID_EXIT, CSimpleFrame::OnExit) // In case we add a menu with EXIT to Simple GUI EVT_FRAME_CONNECT(CSimpleFrame::OnConnect) EVT_FRAME_RELOADSKIN(CSimpleFrame::OnReloadSkin) EVT_TIMER(ID_SIMPLEFRAMERENDERTIMER, CSimpleFrame::OnFrameRender)