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