1
// Berkeley Open Infrastructure for Network Computing
2
// http://boinc.berkeley.edu
3
// Copyright (C) 2005 University of California
5
// This is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation;
8
// either version 2.1 of the License, or (at your option) any later version.
10
// This software 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.
15
// To view the GNU Lesser General Public License visit
16
// http://www.gnu.org/copyleft/lesser.html
17
// or write to the Free Software Foundation, Inc.,
18
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
#if defined(__GNUG__) && !defined(__APPLE__)
21
#pragma implementation "BOINCGUIApp.h"
25
#include <Carbon/Carbon.h>
28
#if (defined(SANDBOX) && defined(_DEBUG))
29
#include "SetupSecurity.h"
35
#include "diagnostics.h"
42
#include "common/wxFlatNotebook.h"
44
#include "BOINCGUIApp.h"
45
#include "SkinManager.h"
46
#include "MainDocument.h"
47
#include "BOINCClientManager.h"
48
#include "BOINCTaskBar.h"
49
#include "BOINCBaseFrame.h"
50
#include "AdvancedFrame.h"
51
#include "sg_ImageLoader.h"
52
#include "sg_StatImageLoader.h"
53
#include "sg_BoincSimpleGUI.h"
54
#include "DlgExitMessage.h"
56
static bool s_bSkipExitConfirmation = false;
59
EXTERN_C BOOL ClientLibraryStartup();
60
EXTERN_C BOOL IdleTrackerAttach();
61
EXTERN_C void IdleTrackerDetach();
62
EXTERN_C void ClientLibraryShutdown();
63
EXTERN_C DWORD BOINCGetIdleTickCount();
67
IMPLEMENT_APP(CBOINCGUIApp)
68
IMPLEMENT_DYNAMIC_CLASS(CBOINCGUIApp, wxApp)
71
bool CBOINCGUIApp::OnInit() {
73
// Setup variables with default values
74
m_strBOINCArguments = wxEmptyString;
75
m_strBOINCMGRRootDirectory = wxEmptyString;
76
m_strBOINCMGRDataDirectory = wxEmptyString;
78
m_pSkinManager = NULL;
81
m_pTaskBarIcon = NULL;
83
m_pMacSystemMenu = NULL;
84
printf("Using %s.\n", wxVERSION_STRING); // For debugging
87
m_strDefaultWindowStation = wxEmptyString;
88
m_strDefaultDesktop = wxEmptyString;
89
m_strDefaultDisplay = wxEmptyString;
90
m_bBOINCMGRAutoStarted = false;
91
m_iBOINCMGRDisableAutoStart = 0;
92
m_iShutdownCoreClient = 0;
93
m_iDisplayExitDialog = 1;
94
m_iGUISelected = BOINC_SIMPLEGUI;
96
m_hClientLibraryDll = NULL;
99
#if (defined(SANDBOX) || defined(__WXMAC__))
104
g_use_sandbox = true;
106
g_use_sandbox = false;
109
// Initialize local variables
110
int iSelectedLanguage = 0;
111
wxString strDesiredSkinName = wxEmptyString;
112
wxString strDialogMessage = wxEmptyString;
114
// Commandline parsing is done in wxApp::OnInit()
115
if (!wxApp::OnInit()) {
121
umask (2); // Set file creation mask to be writable by both user and group
122
// Our umask will be inherited by all our child processes
125
// Setup application and company information
126
SetAppName(wxT("BOINC Manager"));
127
SetVendorName(wxT("Space Sciences Laboratory, U.C. Berkeley"));
129
// Initialize the configuration storage module
130
m_pConfig = new wxConfig(GetAppName());
131
wxConfigBase::Set(m_pConfig);
134
m_pConfig->SetPath(wxT("/"));
136
// Restore Application State
137
m_pConfig->Read(wxT("AutomaticallyShutdownClient"), &m_iShutdownCoreClient, 0L);
138
m_pConfig->Read(wxT("DisplayShutdownClientDialog"), &m_iDisplayExitDialog, 1L);
139
m_pConfig->Read(wxT("DisableAutoStart"), &m_iBOINCMGRDisableAutoStart, 0L);
140
m_pConfig->Read(wxT("Language"), &iSelectedLanguage, 0L);
141
m_pConfig->Read(wxT("GUISelection"), &m_iGUISelected, BOINC_SIMPLEGUI);
144
// Should we abort the BOINC Manager startup process?
145
if (m_bBOINCMGRAutoStarted && m_iBOINCMGRDisableAutoStart) {
152
// Determine BOINCMgr Data Directory
156
LPTSTR lpszRegistryValue = NULL;
159
// change the current directory to the boinc data directory if it exists
160
lReturnValue = RegOpenKeyEx(
162
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
167
if (lReturnValue == ERROR_SUCCESS) {
168
// How large does our buffer need to be?
169
lReturnValue = RegQueryValueEx(
177
if (lReturnValue != ERROR_FILE_NOT_FOUND) {
178
// Allocate the buffer space.
179
lpszRegistryValue = (LPTSTR) malloc(dwSize);
180
(*lpszRegistryValue) = NULL;
183
lReturnValue = RegQueryValueEx(
188
(LPBYTE)lpszRegistryValue,
192
SetCurrentDirectory(lpszRegistryValue);
194
// Store the root directory for later use.
195
m_strBOINCMGRDataDirectory = lpszRegistryValue;
200
if (hkSetupHive) RegCloseKey(hkSetupHive);
201
if (lpszRegistryValue) free(lpszRegistryValue);
205
// Determine BOINCMgr Root Directory
207
TCHAR szPath[MAX_PATH-1];
209
// change the current directory to the boinc install directory
210
GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR)));
212
TCHAR *pszProg = strrchr(szPath, '\\');
214
szPath[pszProg - szPath + 1] = 0;
217
// Store the root directory for later use.
218
m_strBOINCMGRRootDirectory = szPath;
224
#if wxCHECK_VERSION(2,8,0)
225
// In wxMac-2.8.7, default wxListCtrl::RefreshItem() does not work
226
// so use traditional generic implementation.
227
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
230
wxString strDirectory = wxEmptyString;
232
ProcessSerialNumber psn;
234
// Set the current directory ahead of the application launch so the core
235
// client can find its files
237
// The mac installer sets the "setuid & setgid" bits for the
238
// BOINC Manager and core client so any user can run them and
239
// they can operate on shared data.
240
strDirectory = wxT("/Library/Application Support/");
242
success = ::wxSetWorkingDirectory(strDirectory);
244
// If SetWD failed, don't create a directory in wrong place
245
strDirectory += wxT("BOINC Data"); // We don't customize BOINC Data directory name for branding
246
if (! g_use_sandbox) {
247
if (! wxDirExists(strDirectory))
248
success = wxMkdir(strDirectory, 0777); // Does nothing if dir exists
250
success = ::wxSetWorkingDirectory(strDirectory);
251
// wxChar *wd = wxGetWorkingDirectory(buf, 1000); // For debugging
254
if (!success) // wxSetWorkingDirectory("/Library/Application Support/BOINC Data") FAILED
259
// Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox
261
#if (defined(__WXMAC__) && defined(_DEBUG)) // TODO: implement this for other platforms
262
// GDB can't attach to applications which are running as a different user
263
// or group, so fix up data with current user and group during debugging
264
if (check_security(g_use_sandbox, true)) {
265
CreateBOINCUsersAndGroups();
266
SetBOINCDataOwnersGroupsAndPermissions();
267
SetBOINCAppOwnersGroupsAndPermissions(NULL);
269
#endif // __WXMAC__ && _DEBUG
270
errCode = check_security(g_use_sandbox, true);
274
wxString strDialogMessage = wxEmptyString;
275
strDialogMessage.Printf(
276
_("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)"),
279
wxMessageDialog* pDlg = new wxMessageDialog(NULL, strDialogMessage, wxT(""), wxOK);
280
GetCurrentProcess(&psn);
281
SetFrontProcess(&psn); // Shows process if hidden
289
// Initialize the BOINC Diagnostics Framework
290
int dwDiagnosticsFlags =
291
BOINC_DIAG_DUMPCALLSTACKENABLED |
292
BOINC_DIAG_HEAPCHECKENABLED |
293
BOINC_DIAG_MEMORYLEAKCHECKENABLED |
294
#if defined(__WXMSW__) || defined(__WXMAC__)
295
BOINC_DIAG_REDIRECTSTDERR |
296
BOINC_DIAG_REDIRECTSTDOUT |
298
BOINC_DIAG_TRACETOSTDOUT;
306
// Enable Logging and Trace Masks
307
m_pLog = new wxLogBOINC();
308
wxLog::SetActiveTarget(m_pLog);
310
m_pLog->AddTraceMask(wxT("Function Start/End"));
311
m_pLog->AddTraceMask(wxT("Function Status"));
313
// Enable known image types
314
wxImage::AddHandler(new wxXPMHandler);
315
wxImage::AddHandler(new wxPNGHandler);
316
wxImage::AddHandler(new wxGIFHandler);
317
wxImage::AddHandler(new wxICOHandler);
319
// Initialize the internationalization module
320
m_pLocale = new wxLocale();
323
// Look for the localization files by absolute and relative locations.
324
// preference given to the absolute location.
325
m_pLocale->Init(iSelectedLanguage);
326
if (!m_strBOINCMGRRootDirectory.IsEmpty()) {
327
m_pLocale->AddCatalogLookupPathPrefix(
328
wxString(m_strBOINCMGRRootDirectory + wxT("locale"))
331
m_pLocale->AddCatalogLookupPathPrefix(wxT("locale"));
332
m_pLocale->AddCatalog(wxT("BOINC Manager"));
334
InitSupportedLanguages();
336
// Note: JAWS for Windows will only speak the context-sensitive
337
// help if you use this help provider:
338
wxHelpProvider::Set(new wxHelpControllerHelpProvider());
340
// Initialize the skin manager
341
m_pSkinManager = new CSkinManager();
342
wxASSERT(m_pSkinManager);
344
m_pSkinManager->ReloadSkin(
346
m_pConfig->Read(wxT("Skin"),
347
m_pSkinManager->GetDefaultSkinName())
351
// Perform any last minute checks that should keep the manager
353
wxString strRebootPendingFile =
354
GetRootDirectory() + wxFileName::GetPathSeparator() + wxT("RebootPending.txt");
356
wxFileInputStream fisRebootPending(strRebootPendingFile);
357
if (fisRebootPending.IsOk()) {
359
wxMessageDialog dialog(
361
_("A reboot is required in order for BOINC to run properly.\nPlease reboot your computer and try again."),
371
// Initialize the main document
372
m_pDocument = new CMainDocument();
373
wxASSERT(m_pDocument);
375
m_pDocument->OnInit();
377
// Is there a condition in which the Simple GUI should not be used?
378
if (BOINC_SIMPLEGUI == m_iGUISelected) {
381
if (wxGetDisplaySize().GetHeight() < 600) {
382
m_iGUISelected = BOINC_ADVANCEDGUI;
385
// Screen reader in use?
387
BOOL bScreenReaderEnabled = false;
388
SystemParametersInfo(SPI_GETSCREENREADER, NULL, &bScreenReaderEnabled, NULL);
389
if (bScreenReaderEnabled) {
390
m_iGUISelected = BOINC_ADVANCEDGUI;
396
#if 0 // We may still need this code; don't remove it yet -- CAF 1/30/08
397
// When running BOINC Client as a daemon / service, the menubar icon is sometimes
398
// unresponsive to mouse clicks if we create it before connecting to the Client.
399
CBOINCClientManager* pcm = m_pDocument->m_pClientManager;
400
if (pcm->IsSystemBooting() && pcm->IsBOINCConfiguredAsDaemon()) {
401
pcm->StartupBOINCCore();
406
// Initialize the task bar icon
407
#if defined(__WXMSW__) || defined(__WXMAC__)
408
m_pTaskBarIcon = new CTaskBarIcon(
409
m_pSkinManager->GetAdvanced()->GetApplicationName(),
410
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
411
m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(),
412
m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon()
414
wxASSERT(m_pTaskBarIcon);
417
// Detect the display info and store for later use.
420
// Startup the System Idle Detection code
421
ClientLibraryStartup();
425
s_bSkipExitConfirmation = false;
426
AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false );
428
m_pMacSystemMenu = new CMacSystemMenu(
429
m_pSkinManager->GetAdvanced()->GetApplicationName(),
430
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
431
m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(),
432
m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon()
434
wxASSERT(m_pMacSystemMenu);
436
ProcessInfoRec pInfo;
439
GetCurrentProcess(&psn);
440
memset(&pInfo, 0, sizeof(pInfo));
441
pInfo.processInfoLength = sizeof( ProcessInfoRec );
442
err = GetProcessInformation(&psn, &pInfo);
444
psn = pInfo.processLauncher;
445
memset(&pInfo, 0, sizeof(pInfo));
446
pInfo.processInfoLength = sizeof( ProcessInfoRec );
447
err = GetProcessInformation(&psn, &pInfo);
449
// Don't open main window if we were started automatically at login
450
if (pInfo.processSignature == 'lgnw') { // Login Window app
451
m_bGUIVisible = false;
453
// If the system was just started, we usually get a "Connection
454
// failed" error if we try to connect too soon, so delay a bit.
460
SetActiveGUI(m_iGUISelected, false);
462
SetActiveGUI(m_iGUISelected);
465
GetCurrentProcess(&psn);
466
ShowHideProcess(&psn, false);
474
int CBOINCGUIApp::OnExit() {
475
// Shutdown the System Idle Detection code
477
ClientLibraryShutdown();
480
m_pDocument->OnExit();
484
if (m_pSkinManager) {
485
m_pConfig->Write(wxT("Skin"), m_pSkinManager->GetSelectedSkin());
486
delete m_pSkinManager;
493
// Save Application State
494
m_pConfig->Write(wxT("AutomaticallyShutdownClient"), m_iShutdownCoreClient);
495
m_pConfig->Write(wxT("DisplayShutdownClientDialog"), m_iDisplayExitDialog);
496
m_pConfig->Write(wxT("DisableAutoStart"), m_iBOINCMGRDisableAutoStart);
498
diagnostics_finish();
500
return wxApp::OnExit();
504
void CBOINCGUIApp::OnInitCmdLine(wxCmdLineParser &parser) {
505
wxApp::OnInitCmdLine(parser);
506
static const wxCmdLineEntryDesc cmdLineDesc[] = {
507
{ wxCMD_LINE_SWITCH, wxT("a"), wxT("autostart"), _("BOINC Manager was started by the operating system automatically")},
508
{ wxCMD_LINE_SWITCH, wxT("s"), wxT("systray"), _("Startup BOINC so only the system tray icon is visible")},
509
{ wxCMD_LINE_SWITCH, wxT("b"), wxT("boincargs"), _("Startup BOINC with these optional arguments")},
510
{ wxCMD_LINE_SWITCH, wxT("i"), wxT("insecure"), _("disable BOINC security users and permissions")},
511
{ wxCMD_LINE_NONE} //DON'T forget this line!!
513
parser.SetDesc(cmdLineDesc);
517
bool CBOINCGUIApp::OnCmdLineParsed(wxCmdLineParser &parser) {
518
// Give default processing (-?, --help and --verbose) the chance to do something.
519
wxApp::OnCmdLineParsed(parser);
520
parser.Found(wxT("boincargs"), &m_strBOINCArguments);
521
if (parser.Found(wxT("autostart"))) {
522
m_bBOINCMGRAutoStarted = true;
524
if (parser.Found(wxT("systray"))) {
525
m_bGUIVisible = false;
527
if (parser.Found(wxT("insecure"))) {
528
g_use_sandbox = false;
534
void CBOINCGUIApp::DetectDisplayInfo() {
536
wxChar szWindowStation[256];
537
memset(szWindowStation, 0, sizeof(szWindowStation)/sizeof(wxChar));
538
wxChar szDesktop[256];
539
memset(szDesktop, 0, sizeof(szDesktop)/sizeof(wxChar));
541
if (wxWIN95 != wxGetOsVersion(NULL, NULL)) {
542
// Retrieve the current window station and desktop names
543
GetUserObjectInformation(
544
GetProcessWindowStation(),
547
(sizeof(szWindowStation) / sizeof(wxChar)),
550
GetUserObjectInformation(
551
GetThreadDesktop(GetCurrentThreadId()),
554
(sizeof(szDesktop) / sizeof(wxChar)),
557
m_strDefaultWindowStation = szWindowStation;
558
m_strDefaultDesktop = szDesktop;
562
wxString p = wxString(getenv("DISPLAY"), wxConvUTF8);
563
if (p) m_strDefaultDisplay = p;
569
void CBOINCGUIApp::InitSupportedLanguages() {
571
const wxLanguageInfo* liLanguage = NULL;
574
m_astrLanguages.Insert(wxEmptyString, 0, wxLANGUAGE_USER_DEFINED+1);
576
// These are just special tags so deal with them in a special way
577
m_astrLanguages[wxLANGUAGE_DEFAULT] = _("(Automatic Detection)");
578
m_astrLanguages[wxLANGUAGE_UNKNOWN] = _("(Unknown)");
579
m_astrLanguages[wxLANGUAGE_USER_DEFINED] = _("(User Defined)");
581
for (iIndex = 0; iIndex <= wxLANGUAGE_USER_DEFINED; iIndex++) {
582
liLanguage = wxLocale::GetLanguageInfo(iIndex);
584
m_astrLanguages[iIndex] = liLanguage->Description;
592
// Set s_bSkipExitConfirmation to true if cancelled because of logging out or shutting down
593
OSErr CBOINCGUIApp::QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) {
596
ProcessSerialNumber SenderPSN, ourPSN;
598
ProcessInfoRec pInfo;
602
// Refuse to quit if a modal dialog is open. Search for the dialog
603
// by ID since all of BOINC Manager's dialog IDs are 10000.
604
// Unfortunately, I know of no way to disable the Quit item in our Dock menu
605
if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) {
607
return userCanceledErr;
610
anErr = AEGetAttributePtr(appleEvt, keyAddressAttr, typeProcessSerialNumber,
611
&senderType, &SenderPSN, sizeof(SenderPSN), &actualSize);
613
if (anErr == noErr) {
615
GetCurrentProcess(&ourPSN);
617
anErr = SameProcess(&SenderPSN, &ourPSN, &isSame);
619
if (anErr == noErr) {
622
pInfo.processInfoLength = sizeof( ProcessInfoRec );
623
pInfo.processName = NULL;
624
pInfo.processAppSpec = &fileSpec;
626
anErr = GetProcessInformation(&SenderPSN, &pInfo);
628
// Consider a Quit command from our Dock menu as coming from this application
629
if (pInfo.processSignature != 'dock') {
630
s_bSkipExitConfirmation = true; // Not from our app, our dock icon or our taskbar icon
631
wxGetApp().ExitMainLoop(); // Prevents wxMac from issuing events to closed frames
637
return wxGetApp().MacHandleAEQuit((AppleEvent*)appleEvt, reply);
643
int CBOINCGUIApp::ClientLibraryStartup() {
645
::ClientLibraryStartup();
651
int CBOINCGUIApp::IdleTrackerAttach() {
653
::IdleTrackerAttach();
659
int CBOINCGUIApp::IdleTrackerDetach() {
661
::IdleTrackerDetach();
667
int CBOINCGUIApp::ClientLibraryShutdown() {
669
::ClientLibraryShutdown();
675
int CBOINCGUIApp::UpdateSystemIdleDetection() {
677
return BOINCGetIdleTickCount();
684
int CBOINCGUIApp::StartBOINCScreensaverTest() {
686
wxString strExecute = wxEmptyString;
687
wxChar szExecutableDirectory[4096];
688
memset(szExecutableDirectory, 0, sizeof(szExecutableDirectory));
690
// On Windows the screensaver is located in the Windows directory.
692
szExecutableDirectory,
693
(sizeof(szExecutableDirectory) / sizeof(wxChar))
696
// Append boinc.scr to the end of the strExecute string and get ready to rock
697
strExecute = wxT("\"") + wxString(szExecutableDirectory) + wxT("\\boinc.scr\" /t");
698
::wxExecute(strExecute);
704
// The skin has changed and all UI elements need to reload their bitmaps.
706
void CBOINCGUIApp::FireReloadSkin() {
708
m_pFrame->FireReloadSkin();
710
if (m_pTaskBarIcon) {
711
m_pTaskBarIcon->FireReloadSkin();
716
bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) {
717
CBOINCBaseFrame* pNewFrame = NULL;
718
CBOINCBaseFrame* pOldFrame = m_pFrame;
720
// Create the new window
721
if ((iGUISelection != m_iGUISelected) || !m_pFrame) {
722
switch(iGUISelection) {
723
case BOINC_SIMPLEGUI:
725
// Initialize the simple gui window
726
pNewFrame = new CSimpleFrame(
727
m_pSkinManager->GetAdvanced()->GetApplicationName(),
728
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
729
m_pSkinManager->GetAdvanced()->GetApplicationIcon32()
732
case BOINC_ADVANCEDGUI:
733
// Initialize the advanced gui window
734
pNewFrame = new CAdvancedFrame(
735
m_pSkinManager->GetAdvanced()->GetApplicationName(),
736
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
737
m_pSkinManager->GetAdvanced()->GetApplicationIcon32()
744
SetTopWindow(pNewFrame);
746
// Store the new frame for future use
747
m_pFrame = pNewFrame;
749
// Hide the old one if it exists. We must do this
750
// after updating m_pFrame to prevent Mac OSX from
751
// hiding the application
752
if (pOldFrame) pOldFrame->Hide();
754
// Show the new frame if needed
755
if (pNewFrame && bShowWindow) pNewFrame->Show();
757
// Delete the old one if it exists
758
if (pOldFrame) pOldFrame->Destroy();
762
// Show the new frame if needed
763
if (m_pFrame && bShowWindow) m_pFrame->Show();
765
m_iGUISelected = iGUISelection;
766
m_pConfig->Write(wxT("GUISelection"), iGUISelection);
772
int CBOINCGUIApp::ConfirmExit() {
773
CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
774
CMainDocument* pDoc = wxGetApp().GetDocument();
775
wxString strConnectedCompter = wxEmptyString;
779
wxASSERT(pSkinAdvanced);
780
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
781
wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
783
// If we are connected to the local core client and the manager is exiting
784
// give the user the option to shutdown the core client, even if the
785
// manager didn't launch the core client anyway.
786
if (!pDoc->m_pClientManager->WasBOINCStartedByManager()) {
787
pDoc->GetConnectedComputerName(strConnectedCompter);
788
if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
789
// Don't shutdown remote clients
795
// Don't run confirmation dialog if logging out or shutting down
796
if (s_bSkipExitConfirmation)
799
if (!m_iDisplayExitDialog) {
800
return 1; // User doesn't want to display the dialog and wants to shutdown the client.
803
if (!m_iDisplayExitDialog) {
804
return 1; // User doesn't want to display the dialog and just wants to use their previous value
809
// Don't run confirmation dialog if logging out or shutting down
810
if (s_bSkipExitConfirmation)
813
ProcessSerialNumber psn;
815
GetCurrentProcess(&psn);
816
bool wasVisible = IsProcessVisible(&psn);
817
SetFrontProcess(&psn); // Shows process if hidden
820
CDlgExitMessage dlg(NULL);
822
if (!pSkinAdvanced->GetExitMessage().IsEmpty()) {
823
dlg.m_DialogExitMessage->SetLabel(pSkinAdvanced->GetExitMessage());
827
if (m_iShutdownCoreClient) {
828
dlg.m_DialogShutdownCoreClient->SetValue(TRUE);
832
if (m_iDisplayExitDialog) {
833
dlg.m_DialogDisplay->SetValue(FALSE);
839
if (wxID_OK == dlg.ShowModal()) {
841
s_bSkipExitConfirmation = true; // Don't ask twice (only affects Mac)
843
m_iShutdownCoreClient = dlg.m_DialogShutdownCoreClient->GetValue();
845
m_iDisplayExitDialog = !dlg.m_DialogDisplay->GetValue();
852
ShowHideProcess(&psn, false);
860
const char *BOINC_RCSID_487cbf3018 = "$Id: BOINCGUIApp.cpp 16487 2008-11-13 10:57:16Z charlief $";
1
// This file is part of BOINC.
2
// http://boinc.berkeley.edu
3
// Copyright (C) 2008 University of California
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.
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.
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/>.
18
#if defined(__GNUG__) && !defined(__APPLE__)
19
#pragma implementation "BOINCGUIApp.h"
23
#include <Carbon/Carbon.h>
26
#if (defined(SANDBOX) && defined(_DEBUG))
27
#include "SetupSecurity.h"
33
#include "diagnostics.h"
41
#include "common/wxFlatNotebook.h"
42
#include "BOINCInternetFSHandler.h"
43
//#include "BOINCMemoryFSHandler.h"
45
#include "BOINCGUIApp.h"
46
#include "SkinManager.h"
47
#include "MainDocument.h"
48
#include "BOINCClientManager.h"
49
#include "BOINCTaskBar.h"
50
#include "BOINCBaseFrame.h"
51
#include "AdvancedFrame.h"
52
#include "sg_ImageLoader.h"
53
#include "sg_StatImageLoader.h"
54
#include "sg_BoincSimpleGUI.h"
55
#include "DlgExitMessage.h"
56
#include "DlgEventLog.h"
60
DEFINE_EVENT_TYPE(wxEVT_RPC_FINISHED)
62
IMPLEMENT_APP(CBOINCGUIApp)
63
IMPLEMENT_DYNAMIC_CLASS(CBOINCGUIApp, wxApp)
65
BEGIN_EVENT_TABLE (CBOINCGUIApp, wxApp)
66
EVT_RPC_FINISHED(CBOINCGUIApp::OnRPCFinished)
70
bool s_bSkipExitConfirmation = false;
74
// Set s_bSkipExitConfirmation to true if cancelled because of logging out or shutting down
75
OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) {
78
ProcessSerialNumber SenderPSN;
83
// Refuse to quit if a modal dialog is open.
84
// Unfortunately, I know of no way to disable the Quit item in our Dock menu
85
if (wxGetApp().IsModalDialogDisplayed()) {
87
return userCanceledErr;
90
anErr = AEGetAttributePtr(appleEvt, keyAddressAttr, typeProcessSerialNumber,
91
&senderType, &SenderPSN, sizeof(SenderPSN), &actualSize);
94
pInfo.processInfoLength = sizeof( ProcessInfoRec );
95
pInfo.processName = NULL;
96
pInfo.processAppSpec = &fileSpec;
98
anErr = GetProcessInformation(&SenderPSN, &pInfo);
100
// Consider a Quit command from our Dock menu as coming from this application
101
if ( (pInfo.processSignature != 'dock') && (pInfo.processSignature != 'BNC!') ) {
102
s_bSkipExitConfirmation = true; // Not from our app, our dock icon or our taskbar icon
103
wxGetApp().ExitMainLoop(); // Prevents wxMac from issuing events to closed frames
107
return wxGetApp().MacHandleAEQuit((AppleEvent*)appleEvt, reply);
113
bool CBOINCGUIApp::OnInit() {
114
// Initialize globals
116
g_use_sandbox = true;
118
g_use_sandbox = false;
121
s_bSkipExitConfirmation = false;
123
// Initialize class variables
125
m_pSkinManager = NULL;
128
m_pTaskBarIcon = NULL;
131
m_pMacSystemMenu = NULL;
133
m_strBOINCMGRExecutableName = wxEmptyString;
134
m_strBOINCMGRRootDirectory = wxEmptyString;
135
m_strBOINCMGRDataDirectory = wxEmptyString;
136
m_strHostNameArg = wxEmptyString;
137
m_strPasswordArg = wxEmptyString;
138
m_iRPCPortArg = GUI_RPC_PORT;
139
m_strBOINCArguments = wxEmptyString;
140
m_bAccessibilityEnabled = false;
141
m_bGUIVisible = true;
142
m_bDebugSkins = false;
143
m_bMultipleInstancesOK = false;
144
m_strDefaultWindowStation = wxEmptyString;
145
m_strDefaultDesktop = wxEmptyString;
146
m_strDefaultDisplay = wxEmptyString;
147
m_bBOINCMGRAutoStarted = false;
148
m_iBOINCMGRDisableAutoStart = 0;
149
m_iShutdownCoreClient = 0;
150
m_iDisplayExitDialog = 1;
151
m_iGUISelected = BOINC_SIMPLEGUI;
152
m_bSafeMessageBoxDisplayed = 0;
154
m_hClientLibraryDll = NULL;
158
// Initialize local variables
160
int iSelectedLanguage = 0;
161
bool bOpenEventLog = false;
162
wxString strDesiredSkinName = wxEmptyString;
163
wxString strDialogMessage = wxEmptyString;
164
bool success = false;
167
// Configure wxWidgets platform specific code
169
wxSystemOptions::SetOption(wxT("msw.staticbox.optimized-paint"), 0);
172
// In wxMac-2.8.7, default wxListCtrl::RefreshItem() does not work
173
// so use traditional generic implementation.
174
// This has been fixed in wxMac-2.8.8, but the Mac native implementation:
175
// - takes 3 times the CPU time as the Mac generic version.
176
// - seems to always redraw entire control even if asked to refresh only one row.
177
// - causes major flicker of progress bars, (probably due to full redraws.)
178
wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
180
AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false );
182
// Cache the current process serial number
183
GetCurrentProcess(&m_psnCurrentProcess);
187
// Commandline parsing is done in wxApp::OnInit()
188
if (!wxApp::OnInit()) {
193
wxCHANGE_UMASK(2); // Set file creation mask to be writable by both user and group
194
// Our umask will be inherited by all our child processes
197
// Setup application and company information
198
SetAppName(wxT("BOINC Manager"));
199
SetVendorName(wxT("Space Sciences Laboratory, U.C. Berkeley"));
202
// Initialize the configuration storage module
203
m_pConfig = new wxConfig(GetAppName());
204
wxConfigBase::Set(m_pConfig);
208
// Restore Application State
209
m_pConfig->SetPath(wxT("/"));
210
m_pConfig->Read(wxT("AutomaticallyShutdownClient"), &m_iShutdownCoreClient, 0L);
211
m_pConfig->Read(wxT("DisplayShutdownClientDialog"), &m_iDisplayExitDialog, 1L);
212
m_pConfig->Read(wxT("DisableAutoStart"), &m_iBOINCMGRDisableAutoStart, 0L);
213
m_pConfig->Read(wxT("Language"), &iSelectedLanguage, 0L);
214
m_pConfig->Read(wxT("GUISelection"), &m_iGUISelected, BOINC_SIMPLEGUI);
215
m_pConfig->Read(wxT("EventLogOpen"), &bOpenEventLog);
218
// Should we abort the BOINC Manager startup process?
219
if (m_bBOINCMGRAutoStarted && m_iBOINCMGRDisableAutoStart) {
223
// Detect if a program that is defined as an accessibility aid is running
224
DetectAccessibilityEnabled();
226
// Detect where BOINC Manager executable name.
227
DetectExecutableName();
229
// Detect where BOINC Manager was installed too.
230
DetectRootDirectory();
232
// Detect where the BOINC Data files are.
233
DetectDataDirectory();
236
// Switch the current directory to the BOINC Data directory
237
if (!GetDataDirectory().IsEmpty()) {
238
success = wxSetWorkingDirectory(GetDataDirectory());
240
if (!g_use_sandbox) {
241
if (!wxDirExists(GetDataDirectory())) {
242
success = wxMkdir(GetDataDirectory(), 0777); // Does nothing if dir exists
248
if (!success) iErrorCode = -1016;
250
// Initialize the BOINC Diagnostics Framework
251
int dwDiagnosticsFlags =
252
BOINC_DIAG_DUMPCALLSTACKENABLED |
253
BOINC_DIAG_HEAPCHECKENABLED |
254
BOINC_DIAG_MEMORYLEAKCHECKENABLED |
255
#if defined(__WXMSW__) || defined(__WXMAC__)
256
BOINC_DIAG_REDIRECTSTDERR |
257
BOINC_DIAG_REDIRECTSTDOUT |
259
BOINC_DIAG_TRACETOSTDOUT;
268
// Enable Logging and Trace Masks
269
m_pLog = new wxLogBOINC();
270
wxLog::SetActiveTarget(m_pLog);
272
m_pLog->AddTraceMask(wxT("Function Start/End"));
273
m_pLog->AddTraceMask(wxT("Function Status"));
276
// Initialize the internationalization module
278
// On Windows, set all locales for this thread on a per-thread basis
279
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
281
m_pLocale = new wxLocale();
285
// Look for the localization files by absolute and relative locations.
286
// preference given to the absolute location.
287
m_pLocale->Init(iSelectedLanguage);
288
if (!m_strBOINCMGRRootDirectory.IsEmpty()) {
289
m_pLocale->AddCatalogLookupPathPrefix(
290
wxString(m_strBOINCMGRRootDirectory + wxT("locale"))
293
m_pLocale->AddCatalogLookupPathPrefix(wxT("locale"));
294
m_pLocale->AddCatalog(wxT("BOINC-Manager"));
295
m_pLocale->AddCatalog(wxT("BOINC-Client"));
297
InitSupportedLanguages();
300
// Note: JAWS for Windows will only speak the context-sensitive
301
// help if you use this help provider:
302
wxHelpProvider::Set(new wxHelpControllerHelpProvider());
306
// Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox
308
#if (defined(__WXMAC__) && defined(_DEBUG)) // TODO: implement this for other platforms
309
// GDB can't attach to applications which are running as a different user
310
// or group, so fix up data with current user and group during debugging
311
if (check_security(g_use_sandbox, true)) {
312
CreateBOINCUsersAndGroups();
313
SetBOINCDataOwnersGroupsAndPermissions();
314
SetBOINCAppOwnersGroupsAndPermissions(NULL);
317
iErrorCode = check_security(g_use_sandbox, true);
322
ShowApplication(true);
324
if (iErrorCode == -1099) {
326
_("You currently are not authorized to manage the client.\n\nTo run BOINC as this user, please:\n - reinstall BOINC answering \"Yes\" to the question about\n non-administrative users\n or\n - contact your administrator to add you to the 'boinc_master'\n user group.");
328
strDialogMessage.Printf(
329
_("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)"),
334
wxMessageDialog* pDlg = new wxMessageDialog(NULL, strDialogMessage, wxT("BOINC Manager"), wxOK);
345
// Enable known image types
346
wxInitAllImageHandlers();
348
// Enable additional file system type handlers
349
wxFileSystem::AddHandler(new wxMemoryFSHandler);
350
wxFileSystem::AddHandler(new CBOINCInternetFSHandler);
352
// Initialize the skin manager
353
m_pSkinManager = new CSkinManager(m_bDebugSkins);
354
wxASSERT(m_pSkinManager);
357
// Load desired manager skin
358
m_pConfig->Read(wxT("Skin"), &strDesiredSkinName, m_pSkinManager->GetDefaultSkinName());
359
m_pSkinManager->ReloadSkin(
366
// Perform any last minute checks that should keep the manager
368
wxString strRebootPendingFile =
369
GetRootDirectory() + wxFileName::GetPathSeparator() + wxT("RebootPending.txt");
371
if (wxFile::Exists(strRebootPendingFile)) {
372
wxMessageDialog dialog(
374
_("A reboot is required in order for BOINC to run properly.\nPlease reboot your computer and try again."),
384
// Detect if BOINC Manager is already running, if so, bring it into the
385
// foreground and then exit.
386
if (!m_bMultipleInstancesOK) {
387
if (DetectDuplicateInstance()) {
392
// Initialize the main document
393
m_pDocument = new CMainDocument();
394
wxASSERT(m_pDocument);
396
m_pDocument->OnInit();
399
// Is there a condition in which the Simple GUI should not be used?
400
if (BOINC_SIMPLEGUI == m_iGUISelected) {
403
if (wxGetDisplaySize().GetHeight() < 600) {
404
m_iGUISelected = BOINC_ADVANCEDGUI;
407
// Screen reader in use?
408
if (IsAccessibilityEnabled()) {
409
m_iGUISelected = BOINC_ADVANCEDGUI;
414
// Initialize the task bar icon
415
m_pTaskBarIcon = new CTaskBarIcon(
416
m_pSkinManager->GetAdvanced()->GetApplicationName(),
417
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
418
m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(),
419
m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon()
421
wxASSERT(m_pTaskBarIcon);
423
m_pMacSystemMenu = new CMacSystemMenu(
424
m_pSkinManager->GetAdvanced()->GetApplicationName(),
425
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
426
m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(),
427
m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon()
429
wxASSERT(m_pMacSystemMenu);
433
// Detect the display info and store for later use.
437
// Startup the System Idle Detection code
441
ProcessSerialNumber psn;
442
ProcessInfoRec pInfo;
445
memset(&pInfo, 0, sizeof(pInfo));
446
pInfo.processInfoLength = sizeof( ProcessInfoRec );
447
err = GetProcessInformation(&m_psnCurrentProcess, &pInfo);
449
psn = pInfo.processLauncher;
450
memset(&pInfo, 0, sizeof(pInfo));
451
pInfo.processInfoLength = sizeof( ProcessInfoRec );
452
err = GetProcessInformation(&psn, &pInfo);
454
// Don't open main window if we were started automatically at login
455
if (pInfo.processSignature == 'lgnw') { // Login Window app
456
m_bGUIVisible = false;
458
// If the system was just started, we usually get a "Connection
459
// failed" error if we try to connect too soon, so delay a bit.
466
SetActiveGUI(m_iGUISelected, false);
468
SetActiveGUI(m_iGUISelected);
470
ShowApplication(false);
474
DisplayEventLog(m_bGUIVisible);
482
int CBOINCGUIApp::OnExit() {
483
// Shutdown the System Idle Detection code
487
m_pDocument->OnExit();
492
m_pConfig->SetPath(wxT("/"));
493
if (m_pSkinManager) {
494
m_pConfig->Write(wxT("Skin"), m_pSkinManager->GetSelectedSkin());
495
delete m_pSkinManager;
504
m_pEventLog->Destroy();
509
// Save Application State
510
m_pConfig->Write(wxT("AutomaticallyShutdownClient"), m_iShutdownCoreClient);
511
m_pConfig->Write(wxT("DisplayShutdownClientDialog"), m_iDisplayExitDialog);
512
m_pConfig->Write(wxT("DisableAutoStart"), m_iBOINCMGRDisableAutoStart);
514
diagnostics_finish();
516
return wxApp::OnExit();
521
/// Pass the command line parameters and discriptions to wxWidgets for displaying.
523
void CBOINCGUIApp::OnInitCmdLine(wxCmdLineParser &parser) {
524
wxApp::OnInitCmdLine(parser);
525
static const wxCmdLineEntryDesc cmdLineDesc[] = {
526
{ wxCMD_LINE_SWITCH, wxT("a"), wxT("autostart"), _("BOINC Manager was started by the operating system automatically")},
527
#if defined(__WXMSW__) || defined(__WXMAC__)
528
{ wxCMD_LINE_SWITCH, wxT("s"), wxT("systray"), _("Startup BOINC so only the system tray icon is visible")},
530
{ wxCMD_LINE_OPTION, wxT("e"), wxT("clientdir"), _("Directory containing the BOINC Client executable")},
531
{ wxCMD_LINE_OPTION, wxT("d"), wxT("datadir"), _("BOINC data directory")},
533
{ wxCMD_LINE_OPTION, wxT("n"), wxT("namehost"), _("Host name or IP address")},
534
{ wxCMD_LINE_OPTION, wxT("g"), wxT("gui_rpc_port"), _("GUI RPC port number")},
535
{ wxCMD_LINE_OPTION, wxT("p"), wxT("password"), _("Password")},
536
{ wxCMD_LINE_SWITCH, wxT("b"), wxT("boincargs"), _("Startup BOINC with these optional arguments")},
537
{ wxCMD_LINE_SWITCH, wxT("i"), wxT("insecure"), _("disable BOINC security users and permissions")},
538
{ wxCMD_LINE_SWITCH, wxT("c"), wxT("checkskins"), _("set skin debugging mode to enable skin manager error messages")},
539
{ wxCMD_LINE_SWITCH, wxT("m"), wxT("multiple"), _("multiple instances of BOINC Manager allowed")},
540
{ wxCMD_LINE_NONE} //DON'T forget this line!!
542
parser.SetDesc(cmdLineDesc);
547
/// Parse command line parameters.
549
bool CBOINCGUIApp::OnCmdLineParsed(wxCmdLineParser &parser) {
550
// Give default processing (-?, --help and --verbose) the chance to do something.
551
wxApp::OnCmdLineParsed(parser);
552
wxString portNum = wxEmptyString;
554
bool hostNameSpecified = false;
555
bool passwordSpecified = false;
557
parser.Found(wxT("boincargs"), &m_strBOINCArguments);
558
if (parser.Found(wxT("autostart"))) {
559
m_bBOINCMGRAutoStarted = true;
561
#if defined(__WXMSW__) || defined(__WXMAC__)
562
if (parser.Found(wxT("systray"))) {
563
m_bGUIVisible = false;
566
if (parser.Found(wxT("insecure"))) {
567
g_use_sandbox = false;
569
if (parser.Found(wxT("checkskins"))) {
570
m_bDebugSkins = true;
572
if (parser.Found(wxT("multiple"))) {
573
m_bMultipleInstancesOK = true;
576
#if !(defined(__WXMSW__) || defined(__WXMAC__))
577
if (!parser.Found(wxT("clientdir"), &m_strBOINCMGRRootDirectory)) {
578
m_strBOINCMGRRootDirectory = ::wxGetCwd();
580
if (m_strBOINCMGRRootDirectory.Last() != '/') {
581
m_strBOINCMGRRootDirectory.Append('/');
584
if (!parser.Found(wxT("datadir"), &m_strBOINCMGRDataDirectory)) {
585
m_strBOINCMGRDataDirectory = m_strBOINCMGRRootDirectory;
587
if (m_strBOINCMGRDataDirectory.Last() != '/') {
588
m_strBOINCMGRDataDirectory.Append('/');
592
if (parser.Found(wxT("namehost"), &m_strHostNameArg)) {
593
hostNameSpecified = true;
595
m_strHostNameArg = wxT("localhost");
598
if (parser.Found(wxT("gui_rpc_port"), &portNum)) {
599
if (portNum.ToLong(&longPort)) {
600
m_iRPCPortArg = longPort;
602
m_iRPCPortArg = GUI_RPC_PORT; // conversion failed
605
m_iRPCPortArg = GUI_RPC_PORT;
608
if (parser.Found(wxT("password"), &m_strPasswordArg)) {
609
passwordSpecified = true;
611
m_strPasswordArg = wxEmptyString;
614
if (hostNameSpecified && passwordSpecified) {
615
m_bMultipleInstancesOK = true;
622
/// Detect the desktop that BOINC Manager is running in.
624
void CBOINCGUIApp::DetectDisplayInfo() {
626
wxChar szWindowStation[256];
627
memset(szWindowStation, 0, sizeof(szWindowStation)/sizeof(wxChar));
628
wxChar szDesktop[256];
629
memset(szDesktop, 0, sizeof(szDesktop)/sizeof(wxChar));
631
if (wxWIN95 != wxGetOsVersion(NULL, NULL)) {
632
// Retrieve the current window station and desktop names
633
GetUserObjectInformation(
634
GetProcessWindowStation(),
637
(sizeof(szWindowStation) / sizeof(wxChar)),
640
GetUserObjectInformation(
641
GetThreadDesktop(GetCurrentThreadId()),
644
(sizeof(szDesktop) / sizeof(wxChar)),
647
m_strDefaultWindowStation = szWindowStation;
648
m_strDefaultDesktop = szDesktop;
652
wxString p = wxString(getenv("DISPLAY"), wxConvUTF8);
653
if (p) m_strDefaultDisplay = p;
660
/// Detect if an acessibility aid is running on the system.
662
void CBOINCGUIApp::DetectAccessibilityEnabled() {
664
BOOL bScreenReaderEnabled = false;
665
SystemParametersInfo(SPI_GETSCREENREADER, NULL, &bScreenReaderEnabled, NULL);
666
m_bAccessibilityEnabled = (bScreenReaderEnabled == TRUE);
672
/// Detect if another instance of this application is running.
673
// Returns true if there is, otherwise false
675
bool CBOINCGUIApp::DetectDuplicateInstance() {
677
if (CTaskBarIcon::FireAppRestore()) {
682
ProcessSerialNumber PSN;
683
int iInstanceID = wxGetApp().IsAnotherInstanceRunning();
685
// Bring other instance to the front and exit this instance
686
OSStatus err = GetProcessForPID(iInstanceID, &PSN);
687
if (!err) SetFrontProcess(&PSN);
696
/// Determines what name BOINC Manager is called.
698
void CBOINCGUIApp::DetectExecutableName() {
700
TCHAR szPath[MAX_PATH-1];
702
// change the current directory to the boinc install directory
703
GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR)));
705
TCHAR *pszProg = _tcsrchr(szPath, '\\');
710
// Store the root directory for later use.
711
m_strBOINCMGRExecutableName = pszProg;
717
/// Determines where the BOINC Manager is executing from.
719
void CBOINCGUIApp::DetectRootDirectory() {
721
TCHAR szPath[MAX_PATH-1];
723
// change the current directory to the boinc install directory
724
GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR)));
726
TCHAR *pszProg = _tcsrchr(szPath, '\\');
728
szPath[pszProg - szPath + 1] = 0;
731
// Store the root directory for later use.
732
m_strBOINCMGRRootDirectory = szPath;
738
/// Determines where the BOINC data directory is.
740
void CBOINCGUIApp::DetectDataDirectory() {
743
// Determine BOINCMgr Data Directory
747
LPTSTR lpszRegistryValue = NULL;
750
// change the current directory to the boinc data directory if it exists
751
lReturnValue = RegOpenKeyEx(
753
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
758
if (lReturnValue == ERROR_SUCCESS) {
759
// How large does our buffer need to be?
760
lReturnValue = RegQueryValueEx(
768
if (lReturnValue != ERROR_FILE_NOT_FOUND) {
769
// Allocate the buffer space.
770
lpszRegistryValue = (LPTSTR) malloc(dwSize);
771
(*lpszRegistryValue) = NULL;
774
lReturnValue = RegQueryValueEx(
779
(LPBYTE)lpszRegistryValue,
783
// Store the root directory for later use.
784
m_strBOINCMGRDataDirectory = lpszRegistryValue;
789
if (hkSetupHive) RegCloseKey(hkSetupHive);
790
if (lpszRegistryValue) free(lpszRegistryValue);
793
m_strBOINCMGRDataDirectory = wxT("/Library/Application Support/BOINC Data");
798
void CBOINCGUIApp::InitSupportedLanguages() {
800
const wxLanguageInfo* liLanguage = NULL;
803
m_astrLanguages.Insert(wxEmptyString, 0, wxLANGUAGE_USER_DEFINED+1);
805
// These are just special tags so deal with them in a special way
806
m_astrLanguages[wxLANGUAGE_DEFAULT] = _("(Automatic Detection)");
807
m_astrLanguages[wxLANGUAGE_UNKNOWN] = _("(Unknown)");
808
m_astrLanguages[wxLANGUAGE_USER_DEFINED] = _("(User Defined)");
810
for (iIndex = 0; iIndex <= wxLANGUAGE_USER_DEFINED; iIndex++) {
811
liLanguage = wxLocale::GetLanguageInfo(iIndex);
813
m_astrLanguages[iIndex] = liLanguage->Description;
819
int CBOINCGUIApp::IdleTrackerAttach() {
821
::attach_idle_monitor();
827
int CBOINCGUIApp::IdleTrackerDetach() {
829
::detach_idle_monitor();
835
void CBOINCGUIApp::OnRPCFinished( CRPCFinishedEvent& event ) {
836
CMainDocument* pDoc = wxGetApp().GetDocument();
839
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
841
pDoc->OnRPCComplete(event);
845
int CBOINCGUIApp::UpdateSystemIdleDetection() {
847
return get_idle_tick_count();
854
int CBOINCGUIApp::StartBOINCScreensaverTest() {
856
wxString strExecute = wxEmptyString;
857
wxChar szExecutableDirectory[4096];
858
memset(szExecutableDirectory, 0, sizeof(szExecutableDirectory));
860
// On Windows the screensaver is located in the Windows directory.
862
szExecutableDirectory,
863
(sizeof(szExecutableDirectory) / sizeof(wxChar))
866
// Append boinc.scr to the end of the strExecute string and get ready to rock
867
strExecute = wxT("\"") + wxString(szExecutableDirectory) + wxT("\\boinc.scr\" /t");
868
::wxExecute(strExecute);
874
int CBOINCGUIApp::StartBOINCDefaultScreensaverTest() {
876
wxString strExecute = wxEmptyString;
877
strExecute = wxT("\"") + m_strBOINCMGRRootDirectory + wxT("\\boincscr.exe\" --test");
878
::wxExecute(strExecute);
884
// Display the Event Log, it is a modeless dialog not owned by any
886
void CBOINCGUIApp::DisplayEventLog(bool bShowWindow) {
889
m_pEventLog->Raise();
892
m_pEventLog = new CDlgEventLog();
894
m_pEventLog->Show(bShowWindow);
896
m_pEventLog->Raise();
899
m_pFrame->UpdateRefreshTimerInterval();
906
void CBOINCGUIApp::OnEventLogClose() {
909
m_pFrame->UpdateRefreshTimerInterval();
914
// The skin has changed and all UI elements need to reload their bitmaps.
916
void CBOINCGUIApp::FireReloadSkin() {
918
m_pFrame->FireReloadSkin();
920
if (m_pTaskBarIcon) {
921
m_pTaskBarIcon->FireReloadSkin();
926
bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) {
927
CBOINCBaseFrame* pNewFrame = NULL;
928
CBOINCBaseFrame* pOldFrame = m_pFrame;
935
// Create the new window
936
if ((iGUISelection != m_iGUISelected) || !m_pFrame) {
938
// Reterieve the desired window state before creating the
940
if (BOINC_ADVANCEDGUI == iGUISelection) {
941
m_pConfig->SetPath(wxT("/"));
942
m_pConfig->Read(wxT("YPos"), &iTop, 30);
943
m_pConfig->Read(wxT("XPos"), &iLeft, 30);
944
m_pConfig->Read(wxT("Width"), &iWidth, 800);
945
m_pConfig->Read(wxT("Height"), &iHeight, 600);
947
m_pConfig->SetPath(wxT("/Simple"));
948
m_pConfig->Read(wxT("YPos"), &iTop, 30);
949
m_pConfig->Read(wxT("XPos"), &iLeft, 30);
951
m_pConfig->Read(wxT("Width"), &iWidth, 409);
952
m_pConfig->Read(wxT("Height"), &iHeight, 561);
954
m_pConfig->Read(wxT("Width"), &iWidth, 416);
955
m_pConfig->Read(wxT("Height"), &iHeight, 570);
960
// Make sure that the new window is going to be visible
963
Rect titleRect = {iTop, iLeft, iTop+22, iLeft+iWidth };
964
InsetRect(&titleRect, 5, 5); // Make sure at least a 5X5 piece visible
965
RgnHandle displayRgn = NewRgn();
966
CopyRgn(GetGrayRgn(), displayRgn); // Region encompassing all displays
967
Rect menuRect = ((**GetMainDevice())).gdRect;
968
menuRect.bottom = GetMBarHeight() + menuRect.top;
969
RgnHandle menuRgn = NewRgn();
970
RectRgn(menuRgn, &menuRect); // Region hidden by menu bar
971
DiffRgn(displayRgn, menuRgn, displayRgn); // Subtract menu bar retion
972
if (!RectInRgn(&titleRect, displayRgn))
975
DisposeRgn(displayRgn);
977
// If either co-ordinate is less then 0 then set it equal to 0 to ensure
978
// it displays on the screen.
979
if ( iLeft < 0 ) iLeft = 30;
980
if ( iTop < 0 ) iTop = 30;
982
// Read the size of the screen
983
wxInt32 iMaxWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X );
984
wxInt32 iMaxHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
986
// Max sure that it doesn't go off to the right or bottom
987
if ( iLeft + iWidth > iMaxWidth ) iLeft = iMaxWidth - iWidth;
988
if ( iTop + iHeight > iMaxHeight ) iTop = iMaxHeight - iHeight;
991
// Create the main window
993
if (BOINC_ADVANCEDGUI == iGUISelection) {
994
// Initialize the advanced gui window
995
pNewFrame = new CAdvancedFrame(
996
m_pSkinManager->GetAdvanced()->GetApplicationName(),
997
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
998
m_pSkinManager->GetAdvanced()->GetApplicationIcon32(),
999
wxPoint(iLeft, iTop),
1000
wxSize(iWidth, iHeight)
1003
// Initialize the simple gui window
1004
pNewFrame = new CSimpleFrame(
1005
m_pSkinManager->GetAdvanced()->GetApplicationName(),
1006
m_pSkinManager->GetAdvanced()->GetApplicationIcon(),
1007
m_pSkinManager->GetAdvanced()->GetApplicationIcon32(),
1008
wxPoint(iLeft, iTop),
1009
wxSize(iWidth, iHeight)
1013
wxASSERT(pNewFrame);
1016
SetTopWindow(pNewFrame);
1018
// Store the new frame for future use
1019
m_pFrame = pNewFrame;
1021
// Hide the old one if it exists. We must do this
1022
// after updating m_pFrame to prevent Mac OSX from
1023
// hiding the application
1024
if (pOldFrame) pOldFrame->Hide();
1026
// Delete the old one if it exists
1027
// Note: this has the side effect of hiding the Event Log
1028
if (pOldFrame) pOldFrame->Destroy();
1030
// Show the new frame if needed (and show the Event Log if open)
1031
if (pNewFrame && bShowWindow) pNewFrame->Show();
1035
// Show the new frame if needed
1036
if (m_pFrame && !m_pFrame->IsShown() && bShowWindow) {
1040
::SetForegroundWindow((HWND)m_pFrame->GetHWND());
1044
// Raise the frame to the top of the Z order if needed
1045
if (m_pFrame && m_pFrame->IsShown() && bShowWindow) {
1048
::SetForegroundWindow((HWND)m_pFrame->GetHWND());
1052
m_iGUISelected = iGUISelection;
1053
m_pConfig->SetPath(wxT("/"));
1054
m_pConfig->Write(wxT("GUISelection"), iGUISelection);
1060
int CBOINCGUIApp::ConfirmExit() {
1061
CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
1062
CMainDocument* pDoc = wxGetApp().GetDocument();
1063
wxString strConnectedCompter = wxEmptyString;
1068
wxASSERT(pSkinAdvanced);
1069
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
1070
wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
1072
pDoc->GetConnectedComputerName(strConnectedCompter);
1073
if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
1074
// Don't shut down remote clients on Manager exit
1078
// Don't run confirmation dialog if logging out or shutting down Mac,
1079
// or if emergency exit from AsyncRPCDlg
1080
if (s_bSkipExitConfirmation)
1084
if (!m_iDisplayExitDialog) {
1085
return 1; // User doesn't want to display the dialog and wants to shutdown the client.
1088
if (!m_iDisplayExitDialog) {
1089
return 1; // User doesn't want to display the dialog and just wants to use their previous value
1093
bWasVisible = IsApplicationVisible();
1094
ShowApplication(true);
1096
CDlgExitMessage dlg(NULL);
1098
if (!pSkinAdvanced->GetExitMessage().IsEmpty()) {
1099
dlg.m_DialogExitMessage->SetLabel(pSkinAdvanced->GetExitMessage());
1103
if (m_iShutdownCoreClient) {
1104
dlg.m_DialogShutdownCoreClient->SetValue(TRUE);
1108
if (m_iDisplayExitDialog) {
1109
dlg.m_DialogDisplay->SetValue(FALSE);
1115
if (wxID_OK == dlg.ShowModal()) {
1117
s_bSkipExitConfirmation = true; // Don't ask twice (only affects Mac)
1119
m_iShutdownCoreClient = dlg.m_DialogShutdownCoreClient->GetValue();
1121
m_iDisplayExitDialog = !dlg.m_DialogDisplay->GetValue();
1127
ShowApplication(false);
1130
return retval; // User cancelled exit
1134
// Use this instead of wxMessageBox from all tab Views to suppress
1135
// Periodic RPCs. See comment in CMainDocument::RunPeriodicRPCs()
1136
// for a fuller explanation.
1137
int CBOINCGUIApp::SafeMessageBox(const wxString& message, const wxString& caption, long style,
1138
wxWindow *parent, int x, int y )
1142
m_bSafeMessageBoxDisplayed++;
1144
retval = wxMessageBox(message, caption, style, parent, x, y);
1146
m_bSafeMessageBoxDisplayed--;
1153
/// Determines if another instance of BOINC Manager is running.
1156
/// true if another instance of BOINC Manager is running, otherwise false.
1158
/// Note: will always return false on Win95, Win98, WinME
1160
int CBOINCGUIApp::IsAnotherInstanceRunning() {
1161
std::vector<PROCINFO> piv;
1165
int otherInstanceID = 0;
1168
// Look for BOINC Manager in list of all running processes
1169
retval = procinfo_setup(piv);
1170
if (retval) return false; // Should never happen
1173
myPid = (int)GetCurrentProcessId();
1178
// Get the name of this Application
1180
for (unsigned int i=0; i<piv.size(); i++) {
1182
if (pi->id == myPid) {
1183
strncpy(myName, pi->command, sizeof(myName));
1188
if (myName[0] == 0) {
1189
return false; // Should never happen
1192
// Search process list for other applications with same name
1193
for (unsigned int i=0; i<piv.size(); i++) {
1195
if (pi->id == myPid) continue;
1196
if (!strcmp(pi->command, myName)) {
1197
otherInstanceID = pi->id;
1202
return otherInstanceID;
1207
/// Determines if the current process is visible.
1210
/// true if the current process is visible, otherwise false.
1212
bool CBOINCGUIApp::IsApplicationVisible() {
1214
if (IsProcessVisible(&m_psnCurrentProcess)) {
1222
/// Shows or hides the current process.
1225
/// true will show the process, false will hide the process.
1228
void CBOINCGUIApp::ShowApplication(bool bShow) {
1230
SetFrontProcess(&m_psnCurrentProcess);
1232
ShowHideProcess(&m_psnCurrentProcess, false);
1236
void CBOINCGUIApp::ShowApplication(bool) {
1241
bool CBOINCGUIApp::ShowInterface() {
1242
return SetActiveGUI(m_iGUISelected, true);
1246
bool CBOINCGUIApp::ShowNotifications() {
1247
bool retval = false;
1249
retval = SetActiveGUI(m_iGUISelected, true);
1251
GetFrame()->FireNotification();
1252
GetDocument()->UpdateUnreadNoticeState();
1259
bool CBOINCGUIApp::IsModalDialogDisplayed() {
1260
if (m_bSafeMessageBoxDisplayed) return true;
1262
// Search for the dialog by ID since all of BOINC Manager's
1263
// dialog IDs are 10000.
1264
if (wxDynamicCast(wxWindow::FindWindowById(ID_ANYDIALOG), wxDialog)) {
1269
if (m_pDocument->WaitingForRPC()) {
1276
void CBOINCGUIApp::DeleteTaskBarIcon() {
1277
if (m_pTaskBarIcon) {
1278
delete m_pTaskBarIcon;
1280
m_pTaskBarIcon = NULL;
1284
void CBOINCGUIApp::DeleteMacSystemMenu() {
1285
if (m_pMacSystemMenu) {
1286
delete m_pMacSystemMenu;
1288
m_pMacSystemMenu = NULL;
1293
// Prevent recursive entry of CMainDocument::RequestRPC()
1294
int CBOINCGUIApp::FilterEvent(wxEvent &event) {
1295
if (!m_pDocument) return -1;
1296
if (!m_pDocument->WaitingForRPC()) return -1;
1298
// If in RPC Please Wait dialog, reject all command
1299
// and timer events except:
1301
// - those for that dialog or its children
1302
// - Open Manager menu item from system tray icon
1303
int theEventType = event.GetEventType();
1305
if ((theEventType == wxEVT_COMMAND_MENU_SELECTED) && (event.GetId() == wxID_OPEN)) {
1309
wxDialog* theRPCWaitDialog = m_pDocument->GetRPCWaitDialog();
1310
wxObject* theObject = event.GetEventObject();
1312
if (!theObject->IsKindOf(CLASSINFO(wxWindow))) break;
1313
if (theObject == theRPCWaitDialog) return -1;
1314
theObject = ((wxWindow*)theObject)->GetParent();
1317
// Allow all except Command, Timer and Mouse Moved events
1318
if (event.IsCommandEvent()) {
1322
if (theEventType == wxEVT_TIMER) {
1327
if (theEventType == wxEVT_TASKBAR_MOVE) {