1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2017 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #if defined(__GNUG__) && !defined(__APPLE__)
19 #pragma implementation "BOINCGUIApp.h"
20 #endif
21 
22 #ifdef __WXMAC__
23 #include <Carbon/Carbon.h>
24 #include "filesys.h"
25 #include "util.h"
26 #include "mac_util.h"
27 #include "sandbox.h"
28 #endif
29 
30 #include "stdwx.h"
31 #include "diagnostics.h"
32 #include "network.h"
33 #include "util.h"
34 #include "mfile.h"
35 #include "miofile.h"
36 #include "parse.h"
37 #include "idlemon.h"
38 #include "Events.h"
39 #include "LogBOINC.h"
40 #include "BOINCGUIApp.h"
41 #include "SkinManager.h"
42 #include "MainDocument.h"
43 #include "BOINCClientManager.h"
44 #include "BOINCTaskBar.h"
45 #include "BOINCBaseFrame.h"
46 #include "AdvancedFrame.h"
47 #include "DlgExitMessage.h"
48 #include "DlgEventLog.h"
49 #include "procinfo.h"
50 #include "sg_BoincSimpleFrame.h"
51 
52 
53 bool s_bSkipExitConfirmation = false;
54 
55 
56 DEFINE_EVENT_TYPE(wxEVT_RPC_FINISHED)
57 
IMPLEMENT_APP(CBOINCGUIApp)58 IMPLEMENT_APP(CBOINCGUIApp)
59 IMPLEMENT_DYNAMIC_CLASS(CBOINCGUIApp, wxApp)
60 
61 BEGIN_EVENT_TABLE (CBOINCGUIApp, wxApp)
62     EVT_ACTIVATE_APP(CBOINCGUIApp::OnActivateApp)
63     EVT_RPC_FINISHED(CBOINCGUIApp::OnRPCFinished)
64 #ifndef __WXMAC__
65     EVT_END_SESSION(CBOINCGUIApp::OnEndSession)
66 #endif
67 END_EVENT_TABLE ()
68 
69 bool CBOINCGUIApp::OnInit() {
70     // Initialize globals
71 #ifdef SANDBOX
72     g_use_sandbox = true;
73 #else
74     g_use_sandbox = false;
75 #endif
76 
77     s_bSkipExitConfirmation = false;
78     m_bFilterEvents = false;
79     m_bAboutDialogIsOpen = false;
80 
81     // Initialize class variables
82     m_pInstanceChecker = NULL;
83     m_pLocale = NULL;
84     m_pSkinManager = NULL;
85     m_pFrame = NULL;
86     m_pDocument = NULL;
87     m_pTaskBarIcon = NULL;
88     m_pEventLog = NULL;
89     m_bEventLogWasActive = false;
90     m_bProcessingActivateAppEvent = false;
91 #ifdef __WXMAC__
92     m_pMacDockIcon = NULL;
93 #endif
94     m_strBOINCMGRExecutableName = wxEmptyString;
95     m_strBOINCMGRRootDirectory = wxEmptyString;
96     m_strBOINCMGRDataDirectory = wxEmptyString;
97     m_strHostNameArg = wxEmptyString;
98     m_strPasswordArg = wxEmptyString;
99     m_iRPCPortArg = GUI_RPC_PORT;
100     m_strBOINCArguments = wxEmptyString;
101     m_strISOLanguageCode = wxEmptyString;
102     m_bGUIVisible = true;
103     m_bDebugSkins = false;
104     m_bMultipleInstancesOK = false;
105     m_bBOINCMGRAutoStarted = false;
106     m_iBOINCMGRDisableAutoStart = 0;
107     m_iShutdownCoreClient = 0;
108     m_iDisplayExitDialog = 1;
109     m_iDisplayShutdownConnectedClientDialog = 1;
110     m_iGUISelected = BOINC_SIMPLEGUI;
111     m_bSafeMessageBoxDisplayed = 0;
112     m_bRunDaemon = true;
113     m_bNeedRunDaemon = true;
114 
115     // Initialize local variables
116     int      iErrorCode = 0;
117     int      iDesiredLanguageCode = 0;
118     bool     bOpenEventLog = false;
119     wxString strDesiredSkinName = wxEmptyString;
120 #ifdef SANDBOX
121     wxString strDialogMessage = wxEmptyString;
122 #endif
123     bool     success = false;
124 
125 
126     // Configure wxWidgets platform specific code
127 #ifdef __WXMSW__
128     wxSystemOptions::SetOption(wxT("msw.staticbox.optimized-paint"), 0);
129 #endif
130 #ifdef __WXMAC__
131     // In wxMac-2.8.7, default wxListCtrl::RefreshItem() does not work
132     // so use traditional generic implementation.
133     // This has been fixed in wxMac-2.8.8, but the Mac native implementation:
134     //  - takes 3 times the CPU time as the Mac generic version.
135     //  - seems to always redraw entire control even if asked to refresh only one row.
136     //  - causes major flicker of progress bars, (probably due to full redraws.)
137     wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
138 
139     AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false );
140 #endif
141 
142 
143     // Commandline parsing is done in wxApp::OnInit()
144     if (!wxApp::OnInit()) {
145         return false;
146     }
147 
148     if (g_use_sandbox) {
149         wxCHANGE_UMASK(2);  // Set file creation mask to be writable by both user and group
150                             // Our umask will be inherited by all our child processes
151     }
152 
153     // Setup application and company information
154     SetAppName(wxT("BOINC Manager"));
155     SetVendorName(wxT("Space Sciences Laboratory, U.C. Berkeley"));
156 
157 
158     // Initialize the configuration storage module
159     m_pConfig = new wxConfig(GetAppName());
160     wxConfigBase::Set(m_pConfig);
161     wxASSERT(m_pConfig);
162 
163 
164     // Restore Application State
165     m_pConfig->SetPath(wxT("/"));
166     m_pConfig->Read(wxT("AutomaticallyShutdownClient"), &m_iShutdownCoreClient, 0L);
167     m_pConfig->Read(wxT("DisplayShutdownClientDialog"), &m_iDisplayExitDialog, 1L);
168     m_pConfig->Read(wxT("DisplayShutdownConnectedClientDialog"), &m_iDisplayShutdownConnectedClientDialog, 1L);
169     m_pConfig->Read(wxT("DisableAutoStart"), &m_iBOINCMGRDisableAutoStart, 0L);
170     m_pConfig->Read(wxT("LanguageISO"), &m_strISOLanguageCode, wxT(""));
171     m_pConfig->Read(wxT("GUISelection"), &m_iGUISelected, BOINC_SIMPLEGUI);
172     m_pConfig->Read(wxT("EventLogOpen"), &bOpenEventLog);
173     m_pConfig->Read(wxT("RunDaemon"), &m_bRunDaemon, 1L);
174 
175     // Detect if the daemon should be launched
176     m_bNeedRunDaemon = m_bNeedRunDaemon && m_bRunDaemon;
177 
178     // Should we abort the BOINC Manager startup process?
179     if (m_bBOINCMGRAutoStarted && m_iBOINCMGRDisableAutoStart) {
180         return false;
181     }
182 
183     // Detect where BOINC Manager executable name.
184     DetectExecutableName();
185 
186     // Detect where BOINC Manager was installed too.
187     DetectRootDirectory();
188 
189     // Detect where the BOINC Data files are.
190     DetectDataDirectory();
191 
192 
193     // Switch the current directory to the BOINC Data directory
194     if (!GetDataDirectory().IsEmpty()) {
195     	success = wxSetWorkingDirectory(GetDataDirectory());
196         if (!success) {
197             if (!g_use_sandbox) {
198                 if (!wxDirExists(GetDataDirectory())) {
199                     success = wxMkdir(GetDataDirectory(), 0777);    // Does nothing if dir exists
200                 }
201             }
202         }
203     }
204 
205     if (!success) iErrorCode = -1016;
206 
207     // Initialize the BOINC Diagnostics Framework
208     int dwDiagnosticsFlags =
209 #ifdef _DEBUG
210         BOINC_DIAG_HEAPCHECKENABLED |
211         BOINC_DIAG_MEMORYLEAKCHECKENABLED |
212 #endif
213         BOINC_DIAG_DUMPCALLSTACKENABLED |
214         BOINC_DIAG_PERUSERLOGFILES |
215         BOINC_DIAG_REDIRECTSTDERR |
216         BOINC_DIAG_REDIRECTSTDOUT |
217         BOINC_DIAG_TRACETOSTDOUT;
218 
219     diagnostics_init(dwDiagnosticsFlags, "stdoutgui", "stderrgui");
220 
221     // Enable Logging and Trace Masks
222     m_pLog = new wxLogBOINC();
223     wxLog::SetActiveTarget(m_pLog);
224 
225     m_pLog->AddTraceMask(wxT("Function Start/End"));
226     m_pLog->AddTraceMask(wxT("Function Status"));
227 
228 
229     // Initialize the internationalization module
230 #ifdef __WXMSW__
231     // On Windows, set all locales for this thread on a per-thread basis
232     _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
233 #endif
234     m_pLocale = new wxLocale();
235     wxASSERT(m_pLocale);
236 
237     //
238     if (m_strISOLanguageCode.IsEmpty()) {
239         iDesiredLanguageCode = wxLANGUAGE_DEFAULT;
240         m_pLocale->Init(iDesiredLanguageCode);
241         m_strISOLanguageCode = m_pLocale->GetCanonicalName();
242     } else {
243         m_pLocale->Init(wxLocale::FindLanguageInfo(m_strISOLanguageCode)->Language);
244     }
245 
246     // Look for the localization files by absolute and relative locations.
247     //   preference given to the absolute location.
248     if (!m_strBOINCMGRRootDirectory.IsEmpty()) {
249         m_pLocale->AddCatalogLookupPathPrefix(
250             wxString(m_strBOINCMGRRootDirectory + wxT("locale"))
251         );
252     }
253     m_pLocale->AddCatalogLookupPathPrefix(wxT("locale"));
254     m_pLocale->AddCatalog(wxT("BOINC-Manager"));
255     m_pLocale->AddCatalog(wxT("BOINC-Client"));
256     m_pLocale->AddCatalog(wxT("BOINC-Web"));
257 
258     InitSupportedLanguages();
259 
260     // Note: JAWS for Windows will only speak the context-sensitive
261     // help if you use this help provider:
262     wxHelpProvider::Set(new wxHelpControllerHelpProvider());
263 
264     // Enable known image types
265     wxInitAllImageHandlers();
266 
267     // Initialize the skin manager
268     m_pSkinManager = new CSkinManager(m_bDebugSkins);
269     wxASSERT(m_pSkinManager);
270 
271 
272     // Load desired manager skin
273     m_pConfig->Read(wxT("Skin"), &strDesiredSkinName, m_pSkinManager->GetDefaultSkinName());
274     m_pSkinManager->ReloadSkin(strDesiredSkinName);
275 
276 
277 #ifdef SANDBOX
278     // Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox
279     //
280     // NOTE: GDB and LLDB can't attach to applications which are running as
281     // a different user or group.
282     // Normally, the Mac Development (Debug) builds do not define SANDBOX, so
283     // check_security() is never called. However, it is possible to use GDB
284     // or LLDB on sandbox-specific code, as long as the code is run as the
285     // current user (i.e., not as boinc_master or boinc_project), and the
286     // current user is a member of both groups boinc_master and boinc_project.
287     // However, this has not been thoroughly tested. Please see the comments
288     // in SetupSecurity.cpp and check_security.cpp for more details.
289     //
290     char path_to_error[MAXPATHLEN];
291     path_to_error[0] = '\0';
292 
293     if (!iErrorCode) {
294         iErrorCode = check_security(
295             g_use_sandbox, true, path_to_error, sizeof(path_to_error)
296         );
297     }
298 
299     if (iErrorCode) {
300 
301         ShowApplication(true);
302 
303         if (iErrorCode == -1099) {
304 #if (defined(__WXMAC__) && defined (_DEBUG))
305             strDialogMessage.Printf(
306                 "To debug with sandbox security enabled, the current user\n"
307                 "must be a member of both groups boinc_master and boinc_project."
308             );
309 #else   // ! (defined(__WXMAC__) && defined (_DEBUG))
310             strDialogMessage.Printf(
311                 _("You currently are not authorized to manage %s.\n\nTo run %s as this user, please:\n- reinstall %s answering \"Yes\" to the question about non-administrative users\n or\n- contact your administrator to add you to the 'boinc_master' user group."),
312                 m_pSkinManager->GetAdvanced()->GetApplicationShortName().c_str(),
313                 m_pSkinManager->GetAdvanced()->GetApplicationShortName().c_str(),
314                 m_pSkinManager->GetAdvanced()->GetApplicationShortName().c_str()
315             );
316 #endif  // ! (defined(__WXMAC__) && defined (_DEBUG))
317         } else {
318             strDialogMessage.Printf(
319                 _("%s ownership or permissions are not set properly; please reinstall %s.\n(Error code %d"),
320                 m_pSkinManager->GetAdvanced()->GetApplicationShortName().c_str(),
321                 m_pSkinManager->GetAdvanced()->GetApplicationShortName().c_str(),
322                 iErrorCode
323             );
324             if (path_to_error[0]) {
325                 strDialogMessage += _(" at ");
326                 strDialogMessage += wxString::FromUTF8(path_to_error);
327             }
328             strDialogMessage += _(")");
329 
330             fprintf(stderr, "%s\n", (const char*)strDialogMessage.utf8_str());
331         }
332 
333         wxMessageDialog* pDlg = new wxMessageDialog(
334                                     NULL,
335                                     strDialogMessage,
336                                     m_pSkinManager->GetAdvanced()->GetApplicationName(),
337                                     wxOK
338                                     );
339 
340         pDlg->ShowModal();
341         if (pDlg)
342             pDlg->Destroy();
343 
344         return false;
345     }
346 #endif      // SANDBOX
347 
348 
349 #ifdef __WXMSW__
350     // Perform any last minute checks that should keep the manager
351     // from starting up.
352     wxString strRebootPendingFile =
353         GetRootDirectory() + wxFileName::GetPathSeparator() + wxT("RebootPending.txt");
354 
355     if (wxFile::Exists(strRebootPendingFile)) {
356         wxMessageDialog dialog(
357             NULL,
358             _("A reboot is required in order for BOINC to run properly.\nPlease reboot your computer and try again."),
359             _("BOINC Manager"),
360             wxOK|wxICON_ERROR
361         );
362 
363         dialog.ShowModal();
364         return false;
365     }
366 #endif
367 
368 #ifdef __WXMAC__
369     // Prevent a situation where wxSingleInstanceChecker lock file
370     // from last login auto start (with same pid) was not deleted.
371     // This path must match that in DetectDuplicateInstance()
372     wxString lockFilePath = wxString(wxFileName::GetHomeDir() +
373                                         "/Library/Application Support/BOINC/" +
374                                         wxTheApp->GetAppName() +
375                                         '-' + wxGetUserId()
376                                         );
377     if (WasFileModifiedBeforeSystemBoot((char *)(const char*)lockFilePath.utf8_str())) {
378         boinc_delete_file(lockFilePath.utf8_str());
379     }
380 #endif
381 
382     // Detect if BOINC Manager is already running, if so, bring it into the
383     // foreground and then exit.
384     if (DetectDuplicateInstance()) {
385             return false;
386     }
387 
388     // Initialize the main document
389     m_pDocument = new CMainDocument();
390     wxASSERT(m_pDocument);
391 
392     m_pDocument->OnInit();
393 
394 
395     // Is there a condition in which the Simple GUI should not be used?
396     if (BOINC_SIMPLEGUI == m_iGUISelected) {
397         // Screen too small?
398         if (wxGetDisplaySize().GetHeight() < 600) {
399             m_iGUISelected = BOINC_ADVANCEDGUI;
400         }
401     }
402 
403 
404     // Initialize the task bar icon
405 	m_pTaskBarIcon = new CTaskBarIcon(
406         m_pSkinManager->GetAdvanced()->GetApplicationName(),
407         m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
408         m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(),
409         m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon()
410 #ifdef __WXMAC__
411         , wxTBI_CUSTOM_STATUSITEM
412 #endif
413     );
414     wxASSERT(m_pTaskBarIcon);
415 #ifdef __WXMAC__
416     m_pMacDockIcon = new CTaskBarIcon(
417         m_pSkinManager->GetAdvanced()->GetApplicationName(),
418         m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
419         m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(),
420         m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon()
421         , wxTBI_DOCK
422     );
423     wxASSERT(m_pMacDockIcon);
424 #endif
425 
426     // Startup the System Idle Detection code
427     IdleTrackerAttach();
428 
429 #ifdef __WXMAC__
430     // Don't open main window if we were started automatically at login
431     // We are launched hidden if started from our login item (except if
432     // we had windows open at logout, the system "restores" them.)
433     m_bGUIVisible = IsApplicationVisible();
434 
435     if (getTimeSinceBoot() < 30.) {
436         // If the system was just started, we usually get a "Connection
437         // failed" error if we try to connect too soon, so delay a bit.
438         sleep(10);
439     }
440 #endif
441 
442     // Show the UI
443     SetActiveGUI(m_iGUISelected, m_bGUIVisible);
444 
445     if (!m_bGUIVisible) {
446         ShowApplication(false);
447 	}
448 
449     if (bOpenEventLog) {
450         DisplayEventLog(m_bGUIVisible);
451         if (m_bGUIVisible && m_pFrame) {
452             m_pFrame->Raise();
453         }
454     }
455 
456     return true;
457 }
458 
459 #ifdef __WXMAC__
460 // We can "show" (unhide) the main window when the
461 // application is hidden and it won't be visible.
462 // If we don't do this under wxCocoa 3.0, the Dock
463 // icon will bounce (as in notification) when we
464 // click on our menu bar icon.
465 // But wxFrame::Show(true) makes the application
466 // visible again, so we instead call
467 // m_pFrame->wxWindow::Show() here.
468 //
469 // We need to call HideThisApp() after the event
470 // loop is running, so this is called from
471 // CBOINCBaseFrame::OnPeriodicRPC() at the first
472 // firing of ID_PERIODICRPCTIMER.
473 //
OnFinishInit()474 void CBOINCGUIApp::OnFinishInit() {
475     if (!m_bGUIVisible) {
476         HideThisApp();
477 
478         m_pFrame->wxWindow::Show();
479 
480         if (m_pEventLog) {
481             m_pEventLog->wxWindow::Show();
482         }
483     }
484 }
485 #endif
486 
487 
OnExit()488 int CBOINCGUIApp::OnExit() {
489     // Shutdown the System Idle Detection code
490     IdleTrackerDetach();
491 
492 // Under wxWidgets 2.8.0, the task bar icons
493 // must be deleted for app to exit its main loop
494 #ifdef __WXMAC__
495     if (m_pMacDockIcon) {
496         delete m_pMacDockIcon;
497     }
498     m_pMacDockIcon = NULL;
499 #endif
500     if (m_pTaskBarIcon) {
501         delete m_pTaskBarIcon;
502     }
503     m_pTaskBarIcon = NULL;
504 
505     if (m_pDocument) {
506         m_pDocument->OnExit();
507         delete m_pDocument;
508         m_pDocument = NULL;
509     }
510 
511     // Save Application State
512     SaveState();
513 
514     if (m_pSkinManager) {
515         delete m_pSkinManager;
516         m_pSkinManager = NULL;
517     }
518 
519     if (m_pLocale) {
520         delete m_pLocale;
521         m_pLocale = NULL;
522     }
523 
524     if (m_pEventLog) {
525         m_pEventLog->Destroy();
526         m_pEventLog = NULL;
527     }
528 
529     if (m_pInstanceChecker) {
530         delete m_pInstanceChecker;
531         m_pInstanceChecker = NULL;
532     }
533 
534     diagnostics_finish();
535 
536     return wxApp::OnExit();
537 }
538 
539 
540 #ifndef __WXMAC__
541 // Ensure we shut down gracefully on Windows logout or shutdown
OnEndSession(wxCloseEvent &)542 void CBOINCGUIApp::OnEndSession(wxCloseEvent& ) {
543     s_bSkipExitConfirmation = true;
544 
545     // On Windows Vista with UAC turned on, we have to spawn a new process to change the
546     // state of a service.  When Windows is shutting down it'll prevent new processes from
547     // being created.  Sometimes it'll present a crash dialog for the newly spawned application.
548     //
549     // So, we will just let the OS shutdown the service via the service control manager.
550     //
551     if (m_iShutdownCoreClient && m_pDocument->m_pClientManager->IsBOINCConfiguredAsDaemon()) {
552         m_iShutdownCoreClient = false;
553     }
554 
555     CBOINCBaseFrame* pFrame = wxGetApp().GetFrame();
556     wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, wxID_EXIT);
557     // The event loop has already been stopped,
558     // so we must call OnExit directly
559     pFrame->OnExit(evt);
560     OnExit();
561 }
562 #endif
563 
564 
SaveState()565 void CBOINCGUIApp::SaveState() {
566     // Save Application State
567     m_pConfig->SetPath(wxT("/"));
568     if (m_pSkinManager) {
569         m_pConfig->Write(wxT("Skin"), m_pSkinManager->GetSelectedSkin());
570     }
571     m_pConfig->Write(wxT("LanguageISO"), m_strISOLanguageCode);
572     m_pConfig->Write(wxT("AutomaticallyShutdownClient"), m_iShutdownCoreClient);
573     m_pConfig->Write(wxT("DisplayShutdownClientDialog"), m_iDisplayExitDialog);
574     m_pConfig->Write(wxT("DisplayShutdownConnectedClientDialog"), m_iDisplayShutdownConnectedClientDialog);
575     m_pConfig->Write(wxT("DisableAutoStart"), m_iBOINCMGRDisableAutoStart);
576     m_pConfig->Write(wxT("RunDaemon"), m_bRunDaemon);
577 }
578 
579 
580 ///
581 /// Pass the command line parameters and discriptions to wxWidgets for displaying.
582 ///
OnInitCmdLine(wxCmdLineParser & parser)583 void CBOINCGUIApp::OnInitCmdLine(wxCmdLineParser &parser) {
584     wxApp::OnInitCmdLine(parser);
585     parser.AddSwitch("a", "autostart", _("BOINC Manager was started by the operating system automatically"));
586 #if defined(__WXMSW__) || defined(__WXMAC__)
587     parser.AddSwitch("s", "systray", _("Startup BOINC so only the system tray icon is visible"));
588 #else
589     parser.AddOption("e", "clientdir", _("Directory containing the BOINC Client executable"));
590     parser.AddOption("d", "datadir", _("BOINC data directory"));
591 #endif
592     parser.AddOption("n", "namehost", _("Host name or IP address"));
593     parser.AddOption("g", "gui_rpc_port", _("GUI RPC port number"));
594     parser.AddOption("p", "password", _("Password"));
595     parser.AddOption("b", "boincargs", _("Startup BOINC with these optional arguments"));
596     parser.AddSwitch("i","insecure", _("disable BOINC security users and permissions"));
597     parser.AddSwitch("c", "checkskins", _("set skin debugging mode to enable skin manager error messages"));
598     parser.AddSwitch("m", "multiple", _("multiple instances of BOINC Manager allowed"));
599 #if (defined(__WXMAC__) && defined(_DEBUG))
600     parser.AddLongOption("NSDocumentRevisionsDebugMode", _("Not used: workaround for bug in XCode 4.2"));
601 #endif
602     parser.AddSwitch("nd", "no-daemon", _("Not run the daemon"));
603 }
604 
605 
606 ///
607 /// Parse command line parameters.
608 ///
OnCmdLineParsed(wxCmdLineParser & parser)609 bool CBOINCGUIApp::OnCmdLineParsed(wxCmdLineParser &parser) {
610     // Give default processing (-?, --help and --verbose) the chance to do something.
611     wxApp::OnCmdLineParsed(parser);
612     wxString portNum = wxEmptyString;
613     long longPort;
614     bool hostNameSpecified = false;
615     bool passwordSpecified = false;
616 
617     parser.Found(wxT("boincargs"), &m_strBOINCArguments);
618     if (parser.Found(wxT("autostart"))) {
619         m_bBOINCMGRAutoStarted = true;
620     }
621 #if defined(__WXMSW__) || defined(__WXMAC__)
622     if (parser.Found(wxT("systray"))) {
623         m_bGUIVisible = false;
624     }
625 #endif
626     if (parser.Found(wxT("insecure"))) {
627         g_use_sandbox = false;
628     }
629     if (parser.Found(wxT("checkskins"))) {
630         m_bDebugSkins = true;
631     }
632     if (parser.Found(wxT("multiple"))) {
633         m_bMultipleInstancesOK = true;
634     }
635 
636 #if !(defined(__WXMSW__) || defined(__WXMAC__))
637     if (!parser.Found(wxT("clientdir"), &m_strBOINCMGRRootDirectory)) {
638         m_strBOINCMGRRootDirectory = ::wxGetCwd();
639     }
640     if (m_strBOINCMGRRootDirectory.Last() != '/') {
641         m_strBOINCMGRRootDirectory.Append('/');
642     }
643 
644     if (!parser.Found(wxT("datadir"), &m_strBOINCMGRDataDirectory)) {
645         m_strBOINCMGRDataDirectory = m_strBOINCMGRRootDirectory;
646     }
647     if (m_strBOINCMGRDataDirectory.Last() != '/') {
648         m_strBOINCMGRDataDirectory.Append('/');
649     }
650 #endif
651 
652     if (parser.Found(wxT("namehost"), &m_strHostNameArg)) {
653         hostNameSpecified = true;
654     } else {
655         m_strHostNameArg = wxT("localhost");
656     }
657 
658      if (parser.Found(wxT("gui_rpc_port"), &portNum)) {
659         if (portNum.ToLong(&longPort)) {
660             m_iRPCPortArg = longPort;
661         } else {
662             m_iRPCPortArg = GUI_RPC_PORT;  // conversion failed
663         }
664     } else {
665         m_iRPCPortArg = GUI_RPC_PORT;
666     }
667 
668     if (parser.Found(wxT("password"), &m_strPasswordArg)) {
669         passwordSpecified = true;
670     } else {
671         m_strPasswordArg = wxEmptyString;
672     }
673 
674     if (hostNameSpecified && passwordSpecified) {
675         m_bMultipleInstancesOK = true;
676     }
677 
678     if (parser.Found(wxT("no-daemon"))) {
679         m_bNeedRunDaemon = false;
680     }
681     return true;
682 }
683 
684 
685 ///
686 /// Detect if another instance of this application is running.
687 //  Returns true if there is and it is forbidden, otherwise false
688 //
689 // We must initialize m_pInstanceChecker even if m_bMultipleInstancesOK
690 // is true so CMainDocument::OnPoll() can call IsMgrMultipleInstance().
691 ///
DetectDuplicateInstance()692 bool CBOINCGUIApp::DetectDuplicateInstance() {
693 #ifdef __WXMAC__
694     m_pInstanceChecker = new wxSingleInstanceChecker(
695             wxTheApp->GetAppName() + '-' + wxGetUserId(),
696             wxFileName::GetHomeDir() + "/Library/Application Support/BOINC"
697             );
698 #else
699     m_pInstanceChecker = new wxSingleInstanceChecker();
700 #endif
701     if (m_pInstanceChecker->IsAnotherRunning()) {
702         if (m_bMultipleInstancesOK) return false;
703 #ifdef __WXMSW__
704         CTaskBarIcon::FireAppRestore();
705 #endif
706         return true;
707     }
708     return false;
709 }
710 
711 
712 ///
713 /// Determines what name BOINC Manager is called.
714 ///
DetectExecutableName()715 void CBOINCGUIApp::DetectExecutableName() {
716 #ifdef __WXMSW__
717     TCHAR   szPath[MAX_PATH-1];
718 
719     // change the current directory to the boinc install directory
720     GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR)));
721 
722     TCHAR *pszProg = _tcsrchr(szPath, '\\');
723     if (pszProg) {
724         pszProg++;
725     }
726 
727     // Store the root directory for later use.
728     m_strBOINCMGRExecutableName = pszProg;
729 #elif defined(__WXGTK__)
730     char path[PATH_MAX];
731     if (!get_real_executable_path(path, PATH_MAX)) {
732         // find filename component
733         char* name = strrchr(path, '/');
734         if (name) {
735             name++;
736             m_strBOINCMGRExecutableName = name;
737         }
738     }
739 #endif
740 }
741 
742 
743 ///
744 /// Determines where the BOINC Manager is executing from.
745 ///
DetectRootDirectory()746 void CBOINCGUIApp::DetectRootDirectory() {
747 #ifdef __WXMSW__
748     TCHAR   szPath[MAX_PATH-1];
749 
750     // change the current directory to the boinc install directory
751     GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR)));
752 
753     TCHAR *pszProg = _tcsrchr(szPath, '\\');
754     if (pszProg) {
755         szPath[pszProg - szPath + 1] = 0;
756     }
757 
758     // Store the root directory for later use.
759     m_strBOINCMGRRootDirectory = szPath;
760 #elif defined(__WXGTK__)
761     char path[PATH_MAX];
762     if (!get_real_executable_path(path, PATH_MAX)) {
763         // find path component
764         char* name = strrchr(path, '/');
765         if (name) {
766             name++;
767             *name = '\0';
768             m_strBOINCMGRRootDirectory = path;
769         }
770     }
771 #endif
772 }
773 
774 
775 ///
776 /// Determines where the BOINC data directory is.
777 ///
DetectDataDirectory()778 void CBOINCGUIApp::DetectDataDirectory() {
779 #ifdef __WXMSW__
780     //
781     // Determine BOINCMgr Data Directory
782     //
783 	LONG    lReturnValue;
784 	HKEY    hkSetupHive;
785     TCHAR   szPath[MAX_PATH];
786     LPTSTR  lpszValue = NULL;
787     LPTSTR  lpszExpandedValue = NULL;
788     DWORD   dwValueType = REG_EXPAND_SZ;
789     DWORD   dwSize = 0;
790 
791     // change the current directory to the boinc data directory if it exists
792 	lReturnValue = RegOpenKeyEx(
793         HKEY_LOCAL_MACHINE,
794         _T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
795 		0,
796         KEY_READ,
797         &hkSetupHive
798     );
799     if (lReturnValue == ERROR_SUCCESS) {
800         // How large does our buffer need to be?
801         lReturnValue = RegQueryValueEx(
802             hkSetupHive,
803             _T("DATADIR"),
804             NULL,
805             &dwValueType,
806             NULL,
807             &dwSize
808         );
809         if (lReturnValue != ERROR_FILE_NOT_FOUND) {
810             // Allocate the buffer space.
811             lpszValue = (LPTSTR) malloc(dwSize);
812             (*lpszValue) = NULL;
813 
814             // Now get the data
815             lReturnValue = RegQueryValueEx(
816                 hkSetupHive,
817                 _T("DATADIR"),
818                 NULL,
819                 &dwValueType,
820                 (LPBYTE)lpszValue,
821                 &dwSize
822             );
823 
824             // Expand the Strings
825             // We need to get the size of the buffer needed
826             dwSize = 0;
827             lReturnValue = ExpandEnvironmentStrings(lpszValue, NULL, dwSize);
828 
829             if (lReturnValue) {
830                 // Make the buffer big enough for the expanded string
831                 lpszExpandedValue = (LPTSTR) malloc(lReturnValue*sizeof(TCHAR));
832                 (*lpszExpandedValue) = NULL;
833                 dwSize = lReturnValue;
834 
835                 ExpandEnvironmentStrings(lpszValue, lpszExpandedValue, dwSize);
836 
837                 // Store the root directory for later use.
838                 m_strBOINCMGRDataDirectory = lpszExpandedValue;
839             }
840         }
841     } else {
842         if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, szPath))) {
843             _tcsncat(szPath, _T("\\boinc"), ((sizeof(szPath)/sizeof(TCHAR)) - _tcslen(szPath)));
844             if (wxDir::Exists(szPath)) {
845                 // Store the root directory for later use.
846                 m_strBOINCMGRDataDirectory = szPath;
847             }
848         }
849     }
850 
851     // Cleanup
852 	if (hkSetupHive) RegCloseKey(hkSetupHive);
853     if (lpszValue) free(lpszValue);
854     if (lpszExpandedValue) free(lpszExpandedValue);
855 #endif
856 #ifdef __WXMAC__
857     m_strBOINCMGRDataDirectory = wxT("/Library/Application Support/BOINC Data");
858 #endif
859 }
860 
861 
InitSupportedLanguages()862 void CBOINCGUIApp::InitSupportedLanguages() {
863     wxInt32               iIndex = 0;
864     const wxLanguageInfo* liLanguage = NULL;
865 
866     // Prepare the array
867     m_astrLanguages.Insert(wxEmptyString, 0, wxLANGUAGE_USER_DEFINED+1);
868 
869     // These are just special tags so deal with them in a special way
870     m_astrLanguages[wxLANGUAGE_DEFAULT]                    = _("(Automatic Detection)");
871     m_astrLanguages[wxLANGUAGE_UNKNOWN]                    = _("(Unknown)");
872     m_astrLanguages[wxLANGUAGE_USER_DEFINED]               = _("(User Defined)");
873 
874     for (iIndex = 0; iIndex <= wxLANGUAGE_USER_DEFINED; iIndex++) {
875         liLanguage = wxLocale::GetLanguageInfo(iIndex);
876         if (liLanguage) {
877             m_astrLanguages[iIndex] = liLanguage->Description;
878         }
879     }
880 }
881 
882 
IdleTrackerAttach()883 int CBOINCGUIApp::IdleTrackerAttach() {
884 #ifdef __WXMSW__
885     ::attach_idle_monitor();
886 #endif
887     return 0;
888 }
889 
890 
IdleTrackerDetach()891 int CBOINCGUIApp::IdleTrackerDetach() {
892 #ifdef __WXMSW__
893     ::detach_idle_monitor();
894 #endif
895     return 0;
896 }
897 
898 
OnActivateApp(wxActivateEvent & event)899 void CBOINCGUIApp::OnActivateApp(wxActivateEvent& event) {
900     m_bProcessingActivateAppEvent = true;
901 
902     if (event.GetActive()) {
903 #ifdef __WXMAC__
904         ShowInterface();
905 #else
906 #ifdef __WXGTK__
907         // Linux allows the Event Log to be brought forward and made active
908         // even if we have a modal dialog displayed (associated with our
909         // main frame.) This test is needed to allow bringing the modal
910         // dialog forward again by clicking on its title bar.
911         if (!IsModalDialogDisplayed())
912 #endif
913         {
914             bool keepEventLogInFront = m_bEventLogWasActive;
915 
916             if (m_pEventLog && !m_pEventLog->IsIconized() && !keepEventLogInFront) {
917                 m_pEventLog->Raise();
918             }
919             if (m_pFrame) {
920                 m_pFrame->Raise();
921             }
922             if (m_pEventLog && !m_pEventLog->IsIconized() && keepEventLogInFront) {
923                 m_pEventLog->Raise();
924             }
925         }
926 #endif
927     }
928 
929     event.Skip();
930 
931     m_bProcessingActivateAppEvent = false;
932 }
933 
934 
OnRPCFinished(CRPCFinishedEvent & event)935 void CBOINCGUIApp::OnRPCFinished( CRPCFinishedEvent& event ) {
936     CMainDocument*      pDoc = wxGetApp().GetDocument();
937 
938     wxASSERT(pDoc);
939     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
940 
941     pDoc->OnRPCComplete(event);
942 }
943 
944 
UpdateSystemIdleDetection()945 int CBOINCGUIApp::UpdateSystemIdleDetection() {
946 #ifdef __WXMSW__
947     return get_idle_tick_count();
948 #else
949     return TRUE;
950 #endif
951 }
952 
953 
StartBOINCScreensaverTest()954 int CBOINCGUIApp::StartBOINCScreensaverTest() {
955 #ifdef __WXMSW__
956     wxString strExecute = wxEmptyString;
957     wxChar   szExecutableDirectory[4096];
958     memset(szExecutableDirectory, 0, sizeof(szExecutableDirectory));
959 
960     // On Windows the screensaver is located in the Windows directory.
961     GetWindowsDirectory(
962         szExecutableDirectory,
963         (sizeof(szExecutableDirectory) / sizeof(wxChar))
964     );
965 
966     // Append boinc.scr to the end of the strExecute string and get ready to rock
967     strExecute = wxT("\"") + wxString(szExecutableDirectory) + wxT("\\boinc.scr\" /t");
968     ::wxExecute(strExecute);
969 #endif
970     return 0;
971 }
972 
973 
StartBOINCDefaultScreensaverTest()974 int CBOINCGUIApp::StartBOINCDefaultScreensaverTest() {
975 #ifdef __WXMSW__
976     wxString strExecute = wxEmptyString;
977     strExecute = wxT("\"") + m_strBOINCMGRRootDirectory + wxT("\\boincscr.exe\" --test");
978     ::wxExecute(strExecute);
979 #endif
980     return 0;
981 }
982 
983 
984 // Display the Event Log, it is a modeless dialog not owned by
985 // any other UI element.
986 // To work around a Linux bug in wxWidgets 3.0 which prevents
987 // bringing the main frame forward on top of a modeless dialog,
988 // the Event Log is now a wxFrame on Linux only.
DisplayEventLog(bool bShowWindow)989 void CBOINCGUIApp::DisplayEventLog(bool bShowWindow) {
990     if (m_pEventLog) {
991         if (bShowWindow) {
992             if (m_pEventLog->IsIconized()) {
993                 m_pEventLog->Iconize(false);
994             }
995             m_pEventLog->Raise();
996         }
997     } else {
998         m_pEventLog = new CDlgEventLog();
999         if (m_pEventLog) {
1000                 m_pEventLog->Show(bShowWindow);
1001             if (bShowWindow) {
1002                 m_pEventLog->Raise();
1003             }
1004             if (m_pFrame) {
1005                 m_pFrame->UpdateRefreshTimerInterval();
1006             }
1007         }
1008     }
1009 }
1010 
1011 
OnEventLogClose()1012 void CBOINCGUIApp::OnEventLogClose() {
1013     m_pEventLog = NULL;
1014     if (m_pFrame) {
1015         m_pFrame->UpdateRefreshTimerInterval();
1016     }
1017 }
1018 
1019 
1020 // The skin has changed and all UI elements need to reload their bitmaps.
1021 //
FireReloadSkin()1022 void CBOINCGUIApp::FireReloadSkin() {
1023     if (m_pFrame) {
1024 	    m_pFrame->FireReloadSkin();
1025     }
1026     if (m_pTaskBarIcon) {
1027 	    m_pTaskBarIcon->FireReloadSkin();
1028     }
1029 }
1030 
1031 
SetActiveGUI(int iGUISelection,bool bShowWindow)1032 bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) {
1033     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCGUIApp::SetActiveGUI - Function Begin"));
1034     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCGUIApp::SetActiveGUI - GUI Selection: '%d', Show: %d'"), iGUISelection, (int)bShowWindow);
1035 
1036     CBOINCBaseFrame* pNewFrame = NULL;
1037     CBOINCBaseFrame* pOldFrame = m_pFrame;
1038     wxInt32          iTop = 0;
1039     wxInt32          iLeft = 0;
1040     wxInt32          iHeight = 0;
1041     wxInt32          iWidth = 0;
1042     bool             bWindowMaximized = false;
1043 
1044 
1045     // Create the new window
1046     if ((iGUISelection != m_iGUISelected) || !m_pFrame) {
1047 
1048         // Retrieve the desired window state before creating the
1049         //   desired frames
1050         if (BOINC_ADVANCEDGUI == iGUISelection) {
1051             m_pConfig->SetPath(wxT("/"));
1052             m_pConfig->Read(wxT("YPos"), &iTop, 30);
1053             m_pConfig->Read(wxT("XPos"), &iLeft, 30);
1054             m_pConfig->Read(wxT("Width"), &iWidth, 800);
1055             m_pConfig->Read(wxT("Height"), &iHeight, 600);
1056             m_pConfig->Read(wxT("WindowMaximized"), &bWindowMaximized, false);
1057             // Guard against a rare situation where registry values are zero
1058             if (iWidth < 50) iWidth = 800;
1059             if (iHeight < 50) iHeight = 600;
1060         } else {
1061             m_pConfig->SetPath(wxT("/Simple"));
1062             m_pConfig->Read(wxT("YPos"), &iTop, 30);
1063             m_pConfig->Read(wxT("XPos"), &iLeft, 30);
1064 
1065             // We don't save Simple View's width & height since it's
1066             // window is not resizable, so don't try to read them
1067 #ifdef __WXMAC__
1068 //            m_pConfig->Read(wxT("Width"), &iWidth, 409);
1069 //            m_pConfig->Read(wxT("Height"), &iHeight, 561);
1070             iWidth = 409;
1071             iHeight = 561;
1072 #else
1073 //            m_pConfig->Read(wxT("Width"), &iWidth, 416);
1074 //            m_pConfig->Read(wxT("Height"), &iHeight, 570);
1075             iWidth = 416;
1076             iHeight = 570;
1077 #endif
1078         }
1079 
1080 
1081         // Make sure that the new window is going to be visible
1082         //   on a screen
1083 #ifdef __WXMAC__
1084     if (!IsWindowOnScreen(iLeft, iTop, iWidth, iHeight)) {
1085         iTop = iLeft = 30;
1086     }
1087 #else
1088 	    // If either co-ordinate is less then 0 then set it equal to 0 to ensure
1089 	    // it displays on the screen.
1090 	    if ( iLeft < 0 ) iLeft = 30;
1091 	    if ( iTop < 0 ) iTop = 30;
1092 
1093 	    // Read the size of the screen
1094 	    wxInt32 iMaxWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X );
1095 	    wxInt32 iMaxHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
1096 
1097 	    // Max sure that it doesn't go off to the right or bottom
1098 	    if ( iLeft + iWidth > iMaxWidth ) iLeft = iMaxWidth - iWidth;
1099 	    if ( iTop + iHeight > iMaxHeight ) iTop = iMaxHeight - iHeight;
1100 #endif
1101 
1102         // Create the main window
1103         //
1104         if (BOINC_ADVANCEDGUI == iGUISelection) {
1105             // Initialize the advanced gui window
1106             pNewFrame = new CAdvancedFrame(
1107                 m_pSkinManager->GetAdvanced()->GetApplicationName(),
1108                 m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
1109                 wxPoint(iLeft, iTop),
1110                 wxSize(iWidth, iHeight)
1111             );
1112         } else {
1113             // Initialize the simple gui window
1114             pNewFrame = new CSimpleFrame(
1115                 m_pSkinManager->GetAdvanced()->GetApplicationName(),
1116                 m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
1117                 wxPoint(iLeft, iTop),
1118                 wxSize(iWidth, iHeight)
1119             );
1120         }
1121 
1122         wxASSERT(pNewFrame);
1123 
1124         if (pNewFrame) {
1125             SetTopWindow(pNewFrame);
1126 
1127             // Store the new frame for future use
1128             m_pFrame = pNewFrame;
1129 
1130             // Hide the old one if it exists.  We must do this
1131             // after updating m_pFrame to prevent Mac OSX from
1132             // hiding the application
1133             if (pOldFrame) pOldFrame->Hide();
1134 
1135             // Delete the old one if it exists
1136             if (pOldFrame) pOldFrame->Destroy();
1137 
1138             if (iGUISelection != m_iGUISelected) {
1139                 m_iGUISelected = iGUISelection;
1140                 m_pConfig->SetPath(wxT("/"));
1141                 m_pConfig->Write(wxT("GUISelection"), iGUISelection);
1142                 m_pConfig->Flush();
1143             }
1144         }
1145     }
1146 
1147     // Show the new frame if needed
1148     if (!m_bProcessingActivateAppEvent) {
1149         if (m_pFrame && bShowWindow) {
1150             if (m_pEventLog && !m_pEventLog->IsIconized()) {
1151                 m_pEventLog->Show();
1152                 m_pEventLog->Raise();
1153     #ifdef __WXMSW__
1154                 ::SetForegroundWindow((HWND)m_pEventLog->GetHWND());
1155     #endif
1156             }
1157 
1158             if (!m_pFrame->IsShown()) {
1159                 m_pFrame->Show();
1160             }
1161             if (m_pFrame->IsIconized()) {
1162                 m_pFrame->Maximize(false);
1163             }
1164             else if (BOINC_ADVANCEDGUI == iGUISelection && bWindowMaximized) {
1165                 m_pFrame->Maximize();
1166             }
1167             m_pFrame->Raise();
1168 
1169 #ifdef __WXMSW__
1170             ::SetForegroundWindow((HWND)m_pFrame->GetHWND());
1171 #endif
1172         }
1173     }
1174 
1175     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCGUIApp::SetActiveGUI - Function End"));
1176     return true;
1177 }
1178 
1179 
ConfirmExit()1180 int CBOINCGUIApp::ConfirmExit() {
1181     CSkinAdvanced*  pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
1182     CMainDocument*  pDoc = wxGetApp().GetDocument();
1183     wxString        strConnectedCompter = wxEmptyString;
1184     bool            bWasVisible;
1185     int             retval = 0;
1186 
1187     wxASSERT(pDoc);
1188     wxASSERT(pSkinAdvanced);
1189     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
1190     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
1191 
1192     pDoc->GetConnectedComputerName(strConnectedCompter);
1193     if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
1194         // Don't shut down remote clients on Manager exit
1195         return 1;
1196     }
1197 
1198     // Don't run confirmation dialog if logging out or shutting down Mac,
1199     // or if emergency exit from AsyncRPCDlg
1200     if (s_bSkipExitConfirmation) return 1;
1201 
1202     // Don't run confirmation dialog if second instance of Manager
1203     if (IsMgrMultipleInstance()) return 1;
1204 
1205     if (!m_iDisplayExitDialog) {
1206         // Mac: User doesn't want to display the dialog and just wants to use their previous value.
1207         // Win & Linux: User doesn't want to display the dialog and wants to shutdown the client.
1208         return 1;
1209     }
1210 
1211     bWasVisible = IsApplicationVisible();
1212     ShowApplication(true);
1213 
1214     CDlgExitMessage dlg(NULL);
1215 
1216     if (!pSkinAdvanced->GetExitMessage().IsEmpty()) {
1217         dlg.m_DialogExitMessage->SetLabel(pSkinAdvanced->GetExitMessage());
1218     }
1219 
1220 #ifdef __WXMSW__
1221     if (m_iShutdownCoreClient) {
1222         dlg.m_DialogShutdownCoreClient->SetValue(TRUE);
1223     }
1224 #endif
1225 
1226     if (m_iDisplayExitDialog) {
1227         dlg.m_DialogDisplay->SetValue(FALSE);
1228     }
1229 
1230     dlg.Fit();
1231     dlg.Centre();
1232 
1233     if (wxID_OK == dlg.ShowModal()) {
1234 #ifdef __WXMAC__
1235         s_bSkipExitConfirmation = true;     // Don't ask twice (only affects Mac)
1236 #else
1237         m_iShutdownCoreClient = dlg.m_DialogShutdownCoreClient->GetValue();
1238 #endif
1239         m_iDisplayExitDialog = !dlg.m_DialogDisplay->GetValue();
1240         retval = true;
1241 
1242     }
1243 
1244     if (!bWasVisible) {
1245         ShowApplication(false);
1246     }
1247 
1248     return retval;       // User cancelled exit
1249 }
1250 
1251 
1252 // Use this instead of wxMessageBox from all tab Views to suppress
1253 // Periodic RPCs.  See comment in CMainDocument::RunPeriodicRPCs()
1254 // for a fuller explanation.
SafeMessageBox(const wxString & message,const wxString & caption,long style,wxWindow * parent,int x,int y)1255 int CBOINCGUIApp::SafeMessageBox(const wxString& message, const wxString& caption, long style,
1256                  wxWindow *parent, int x, int y )
1257 {
1258     int retval;
1259 
1260     m_bSafeMessageBoxDisplayed++;
1261 
1262     retval = wxMessageBox(message, caption, style, parent, x, y);
1263 
1264     m_bSafeMessageBoxDisplayed--;
1265 
1266     return retval;
1267 }
1268 
1269 
1270 #ifndef __WXMAC__
1271 // See clientgui/mac/BOINCGUIApp.mm for the Mac versions.
1272 ///
1273 /// Determines if the current process is visible.
1274 ///
1275 /// @return
1276 ///  true if the current process is visible, otherwise false.
1277 ///
IsApplicationVisible()1278 bool CBOINCGUIApp::IsApplicationVisible() {
1279     return false;
1280 }
1281 
1282 ///
1283 /// Shows or hides the current process.
1284 ///
1285 /// @param bShow
1286 ///   true will show the process, false will hide the process.
1287 ///
ShowApplication(bool)1288 void CBOINCGUIApp::ShowApplication(bool) {
1289 }
1290 #endif
1291 
1292 
ShowInterface()1293 bool CBOINCGUIApp::ShowInterface() {
1294     ShowApplication(true);
1295     return SetActiveGUI(m_iGUISelected, true);
1296 }
1297 
1298 
ShowNotifications()1299 bool CBOINCGUIApp::ShowNotifications() {
1300     bool retval = false;
1301 
1302     retval = SetActiveGUI(m_iGUISelected, true);
1303     if (retval) {
1304         GetFrame()->FireNotification();
1305         GetDocument()->UpdateUnreadNoticeState();
1306     }
1307 
1308     return retval;
1309 }
1310 
1311 
IsModalDialogDisplayed()1312 bool CBOINCGUIApp::IsModalDialogDisplayed() {
1313     if (m_bSafeMessageBoxDisplayed) return true;
1314 
1315     // Search for the dialog by ID since all of BOINC Manager's
1316     // dialog IDs are 10000.
1317     if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) {
1318         return true;
1319     }
1320 
1321     if (m_pDocument) {
1322         if (m_pDocument->WaitingForRPC()) {
1323             return true;
1324         }
1325     }
1326     return false;
1327 }
1328 
1329 // Prevent recursive entry of CMainDocument::RequestRPC()
FilterEvent(wxEvent & event)1330 int CBOINCGUIApp::FilterEvent(wxEvent &event) {
1331     int theEventType;
1332     wxDialog* theRPCWaitDialog;
1333     wxObject* theObject;
1334 
1335     if (!m_pDocument) return -1;
1336 
1337     theEventType = event.GetEventType();
1338 
1339     if (m_pDocument->WaitingForRPC()) {
1340         // If in RPC Please Wait dialog, reject all command
1341         // and timer events except:
1342         //  - RPC Finished
1343         //  - those for that dialog or its children
1344         //  - Open Manager menu item from system tray icon
1345 
1346         if ((theEventType == wxEVT_COMMAND_MENU_SELECTED) && (event.GetId() == wxID_OPEN)) {
1347             return -1;
1348         }
1349 
1350         theRPCWaitDialog = m_pDocument->GetRPCWaitDialog();
1351         theObject = event.GetEventObject();
1352         while (theObject) {
1353             if (!theObject->IsKindOf(CLASSINFO(wxWindow))) break;
1354             if (theObject == theRPCWaitDialog) return -1;
1355             theObject = ((wxWindow*)theObject)->GetParent();
1356         }
1357         // Continue with rest of filtering below
1358     } else {
1359         // Do limited filtering if shutting down to allow RPC
1360         // completion events but not events which start new RPCs
1361         if (!m_bFilterEvents) return -1;
1362     }
1363 
1364     // Allow all except Command, Timer and Mouse Moved events
1365     if (event.IsCommandEvent()) {
1366         return false;
1367     }
1368 
1369     if (theEventType == wxEVT_TIMER) {
1370         return false;
1371     }
1372 
1373 #ifdef __WXMSW__
1374     if (theEventType == wxEVT_TASKBAR_MOVE) {
1375         return false;
1376     }
1377 #endif
1378 
1379     return -1;
1380 }
1381 
1382