/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2015 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **************************************************************************/ #include "TrayIcon.h" #include "ConfigPath.h" #include "main.h" #include "stringtools.h" #include "TaskBarBaloon.h" #include "Settings.h" #include "Logs.h" #include "TranslationHelper.h" #include "Status.h" #include "CbtStatus.h" #include "Info.h" #include #include #include #include #include #include #include #ifndef _WIN32 #include "../config.h" #include #include #include #include #include #endif #ifdef _WIN32 #include "SelectWindowsComponents.h" #include "SelectRestoreWindowsComponents.h" #include #endif #include /*#if wxUSE_STACKWALKER && defined( __WXDEBUG__ ) // silly workaround for the link error with debug configuration: // \src\common\appbase.cpp wxString wxAppTraitsBase::GetAssertStackTrace() { return wxT(""); } #endif*/ wxDECLARE_APP(MyApp); #ifdef _WIN32 #include #endif #include "SetupWizard.h" #undef _ #define _(s) wxGetTranslation(wxT(s)) std::string ConvertToUTF8(const std::wstring &input); TrayIcon *tray = NULL; MyTimer *timer = NULL; wxString last_status; unsigned int incr_update_intervall=2*60*60+10*60; bool backup_is_running=false; extern bool b_is_pausing; #ifndef DD_RELEASE IMPLEMENT_APP_NO_MAIN(MyApp) #endif #ifndef _WIN32 #undef wxUSE_TASKBARICON_BALLOONS #endif #ifdef _WIN32 HRESULT initCom() { HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL); if (hr != S_OK) { wxMessageBox(wxString::Format(_("CoInitializeSecurity failed: %08x"), hr), wxT("UrBackup"), wxOK | wxICON_ERROR); } return hr; } HRESULT ModifyPrivilege( IN LPCTSTR szPrivilege, IN BOOL fEnable) { HRESULT hr = S_OK; TOKEN_PRIVILEGES NewState; LUID luid; HANDLE hToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { return ERROR_FUNCTION_FAILED; } if (!LookupPrivilegeValue(NULL, szPrivilege, &luid)) { CloseHandle(hToken); return ERROR_FUNCTION_FAILED; } NewState.PrivilegeCount = 1; NewState.Privileges[0].Luid = luid; NewState.Privileges[0].Attributes = (fEnable ? SE_PRIVILEGE_ENABLED : 0); if (!AdjustTokenPrivileges(hToken, FALSE, &NewState, 0, NULL, NULL)) { hr = ERROR_FUNCTION_FAILED; } CloseHandle(hToken); return hr; } #endif #ifdef __APPLE__ extern "C" void bring_to_foreground(); extern "C" void remove_login_item(); extern "C" void check_full_disk_access(); #endif class TheFrame : public wxFrame { public: TheFrame(void) : wxFrame(NULL, -1, wxT("UrBackupGUI")) { } }; namespace { enum ETrayIcon { ETrayIcon_OK, ETrayIcon_PROGRESS, ETrayIcon_ERROR, ETrayIcon_NO_SERVER, ETrayIcon_INDEXING, ETrayIcon_PAUSED, ETrayIcon_NO_RECENT }; ETrayIcon icon_type=ETrayIcon_OK; int needs_restore_restart = 0; int ask_restore_ok = 0; } std::string g_lang="en"; wxString res_path; std::string g_res_path; #if defined(_WIN32) || defined(__APPLE__) wxString ico_ext=wxT("ico"); wxBitmapType ico_type=wxBITMAP_TYPE_ICO; #else wxString ico_ext=wxT("xpm"); wxBitmapType ico_type=wxBITMAP_TYPE_XPM; #endif wxIcon getAppIcon(wxString fn) { int small_sys_x=wxSystemSettings::GetMetric(wxSYS_SMALLICON_X); int small_sys_y=wxSystemSettings::GetMetric(wxSYS_SMALLICON_X); /*wxIconBundle bundle(res_path+fn+wxT(".")+ico_ext); return bundle.GetIcon(wxSize(sys_x, sys_y), wxIconBundle::FALLBACK_NEAREST_LARGER);*/ return wxIcon(res_path+fn+wxT(".")+ico_ext, ico_type, small_sys_x, small_sys_y); } namespace { wxString getPercentDoneText(wxString pc) { wxString pcdone=wxString(_("_percent_ done."))+wxT(" "); pcdone.Replace(wxT("_percent_"), pc + wxT("%")); return pcdone; } } void deleteShellKeys() { #ifdef _WIN32 bool deleted_key; size_t i=0; do { deleted_key=false; if(RegDeleteKeyW(HKEY_CLASSES_ROOT, (L"AllFilesystemObjects\\shell\\urbackup.access."+convert(i)).c_str())==ERROR_SUCCESS) { deleted_key=true; } ++i; } while (deleted_key); #endif } void startOnlyOnce() { #ifndef _WIN32 const char *homedir = NULL; if ((homedir = getenv("HOME")) == NULL) { struct passwd *pw = getpwuid(getuid()); if (pw != NULL) { homedir = pw->pw_dir; } } if (homedir == NULL) { return; } int fd = open((std::string(homedir) + "/.urbackupclientgui_startonce").c_str(), O_CREAT | O_RDWR, S_IRWXU); if (fd == -1) { return; } int rc = flock(fd, LOCK_EX | LOCK_NB); if (rc != 0 && errno==EWOULDBLOCK) { std::cout << "Application is already started" << std::endl; close(fd); exit(30); } #else PWSTR fpathb; HRESULT hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &fpathb); if (hr != S_OK) { return; } std::wstring fpath = fpathb; CoTaskMemFree(fpathb); HANDLE hFile = CreateFileW((fpath + "\\.urbackupclientgui_startonce").c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); if (hFile == INVALID_HANDLE_VALUE) { return; } if (!LockFile(hFile, 0, 0, 100, 0)) { std::cout << "Application is already started" << std::endl; CloseHandle(hFile); exit(30); } #endif } bool MyApp::OnInit() { wxLog::SetLogLevel(0); wxSocketBase::Initialize(); #ifdef _WIN32 wchar_t buf[MAX_PATH]; GetModuleFileNameW(NULL, buf, MAX_PATH); //SetCurrentDirectoryW(ExtractFilePath(buf).c_str() ); g_res_path=ConvertToUTF8(ExtractFilePath(buf))+"\\"; res_path=wxString(g_res_path.c_str(), wxMBConvUTF8()); #elif defined(__APPLE__) wxFileName base(wxStandardPaths::Get().GetExecutablePath()); base.AppendDir(wxT("share")); base.AppendDir(wxT("urbackup")); res_path=base.GetPathWithSep(); g_res_path=res_path; #else res_path=wxT(DATADIR "/urbackup/"); g_res_path= DATADIR "/urbackup/"; #endif wxLanguage lang=wxLANGUAGE_ENGLISH; wxLanguage sysdef=(wxLanguage)wxLocale::GetSystemLanguage(); switch(sysdef) { case wxLANGUAGE_ENGLISH: case wxLANGUAGE_ENGLISH_UK: case wxLANGUAGE_ENGLISH_US: case wxLANGUAGE_ENGLISH_AUSTRALIA: case wxLANGUAGE_ENGLISH_BELIZE: case wxLANGUAGE_ENGLISH_BOTSWANA: case wxLANGUAGE_ENGLISH_CANADA: case wxLANGUAGE_ENGLISH_CARIBBEAN: case wxLANGUAGE_ENGLISH_DENMARK: case wxLANGUAGE_ENGLISH_EIRE: case wxLANGUAGE_ENGLISH_JAMAICA: case wxLANGUAGE_ENGLISH_NEW_ZEALAND: case wxLANGUAGE_ENGLISH_PHILIPPINES: case wxLANGUAGE_ENGLISH_SOUTH_AFRICA: case wxLANGUAGE_ENGLISH_TRINIDAD: case wxLANGUAGE_ENGLISH_ZIMBABWE: lang = sysdef; break; case wxLANGUAGE_GERMAN: case wxLANGUAGE_GERMAN_AUSTRIAN: case wxLANGUAGE_GERMAN_BELGIUM: case wxLANGUAGE_GERMAN_LIECHTENSTEIN: case wxLANGUAGE_GERMAN_LUXEMBOURG: case wxLANGUAGE_GERMAN_SWISS: lang= sysdef; g_lang="de"; break; case wxLANGUAGE_FRENCH: case wxLANGUAGE_FRENCH_BELGIAN: case wxLANGUAGE_FRENCH_CANADIAN: case wxLANGUAGE_FRENCH_LUXEMBOURG: case wxLANGUAGE_FRENCH_MONACO: case wxLANGUAGE_FRENCH_SWISS: lang= sysdef; g_lang="fr"; break; case wxLANGUAGE_RUSSIAN: case wxLANGUAGE_RUSSIAN_UKRAINE: lang= sysdef; g_lang="ru"; break; case wxLANGUAGE_SPANISH: case wxLANGUAGE_SPANISH_ARGENTINA: case wxLANGUAGE_SPANISH_BOLIVIA: case wxLANGUAGE_SPANISH_CHILE: case wxLANGUAGE_SPANISH_COLOMBIA: case wxLANGUAGE_SPANISH_COSTA_RICA: case wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC: case wxLANGUAGE_SPANISH_ECUADOR: case wxLANGUAGE_SPANISH_EL_SALVADOR: case wxLANGUAGE_SPANISH_GUATEMALA: case wxLANGUAGE_SPANISH_HONDURAS: case wxLANGUAGE_SPANISH_MEXICAN: case wxLANGUAGE_SPANISH_MODERN: case wxLANGUAGE_SPANISH_NICARAGUA: case wxLANGUAGE_SPANISH_PANAMA: case wxLANGUAGE_SPANISH_PARAGUAY: case wxLANGUAGE_SPANISH_PERU: case wxLANGUAGE_SPANISH_PUERTO_RICO: case wxLANGUAGE_SPANISH_URUGUAY: case wxLANGUAGE_SPANISH_US: case wxLANGUAGE_SPANISH_VENEZUELA: lang= sysdef; g_lang="es"; break; case wxLANGUAGE_CHINESE: case wxLANGUAGE_CHINESE_SIMPLIFIED: case wxLANGUAGE_CHINESE_HONGKONG: case wxLANGUAGE_CHINESE_MACAU: case wxLANGUAGE_CHINESE_SINGAPORE: lang= sysdef; g_lang="zh_CN"; break; case wxLANGUAGE_CHINESE_TRADITIONAL: case wxLANGUAGE_CHINESE_TAIWAN: lang= sysdef; g_lang="zh_TW"; break; case wxLANGUAGE_PORTUGUESE_BRAZILIAN: lang= sysdef; g_lang="pt_BR"; break; case wxLANGUAGE_PORTUGUESE: lang= sysdef; g_lang="pt"; break; case wxLANGUAGE_ITALIAN: case wxLANGUAGE_ITALIAN_SWISS: lang= sysdef; g_lang="it"; break; case wxLANGUAGE_POLISH: lang= sysdef; g_lang="pl"; break; case wxLANGUAGE_SLOVAK: lang= sysdef; g_lang="sk"; break; case wxLANGUAGE_UKRAINIAN: lang= sysdef; g_lang="uk"; break; case wxLANGUAGE_DANISH: lang= sysdef; g_lang="da"; break; case wxLANGUAGE_DUTCH: case wxLANGUAGE_DUTCH_BELGIAN: lang= sysdef; g_lang="nl"; break; case wxLANGUAGE_FARSI: lang= sysdef; g_lang="fa"; break; case wxLANGUAGE_CZECH: lang= sysdef; g_lang="cz"; break; case wxLANGUAGE_ESTONIAN: lang= sysdef; g_lang="et"; break; case wxLANGUAGE_TURKISH: lang= sysdef; g_lang="tr"; break; case wxLANGUAGE_NORWEGIAN_BOKMAL: case wxLANGUAGE_NORWEGIAN_NYNORSK: lang= sysdef; g_lang="no_NO"; break; case wxLANGUAGE_SWEDISH: case wxLANGUAGE_SWEDISH_FINLAND: lang= sysdef; g_lang="sv"; break; case wxLANGUAGE_FINNISH: lang = sysdef; g_lang = "fi"; break; case wxLANGUAGE_JAPANESE: lang = sysdef; g_lang = "ja"; break; } //std::cout << "Lang: " << g_lang << std::endl; #ifndef _WIN32 m_locale.AddCatalogLookupPathPrefix(res_path); #else m_locale.AddCatalogLookupPathPrefix(res_path+wxT("lang")); #endif m_locale.AddCatalog(L"urbackup"); m_locale.Init(lang, 0); if(!m_locale.IsOk() ) { std::cout << "Selected language is wrong!" << std::endl; } wxImage::AddHandler(new wxPNGHandler()); wxImage::AddHandler(new wxICOHandler()); //wxInitAllImageHandlers(); timer=NULL; wxString cmd; if(argc>1) { cmd=argv[1]; } if(cmd=="daemon") { cmd.clear(); } #ifdef _WIN32 if(cmd.empty()) { writestring(_("&Access/restore backups").ToUTF8().data(), "access_backups_shell_mui.txt"); } #endif #ifdef __WXMAC__ if(!cmd.empty()) { bring_to_foreground(); } #endif if(cmd.empty()) { startOnlyOnce(); SetTopWindow(new TheFrame); tray=new TrayIcon; bool b=tray->SetIcon(getAppIcon(wxT("backup-ok")), wxT("UrBackup Client")); if(!b) { std::cout << "Setting icon failed." << std::endl; } timer=new MyTimer; timer->Start(1000); #ifdef __APPLE__ check_full_disk_access(); #endif } else if(cmd==wxT("settings")) { Settings *s=new Settings(NULL); SetTopWindow(s); s->ShowModal(); s->Destroy(); wxExit(); } else if(cmd==wxT("paths")) { ConfigPath *cp=new ConfigPath(NULL); SetTopWindow(cp); cp->ShowModal(); cp->Destroy(); wxExit(); } else if(cmd==wxT("logs")) { Logs *l=new Logs(NULL); SetTopWindow(l); l->ShowModal(); l->Destroy(); wxExit(); } else if(cmd==wxT("newserver")) { if(argc<3) { return false; } Connector::addNewServer(wxString(argv[2]).ToStdString()); wxExit(); } else if(cmd==wxT("setupWizard")) { if(SetupWizard::runSetupWizard()) { SetupWizard* sw = new SetupWizard(NULL); SetTopWindow(sw); sw->ShowPage(*(sw->m_pages.begin())); sw->SetFocus(); sw->Raise(); sw->ShowModal(); sw->Destroy(); } wxExit(); } else if(cmd==wxT("setupDefault")) { SetupWizard::doDefConfig(); wxExit(); } else if(cmd==wxT("access")) { if(argc<3) { return false; } TrayIcon::accessBackups(wxString(argv[2])); wxExit(); } else if(cmd==wxT("deleteshellkeys")) { deleteShellKeys(); wxExit(); } else if(cmd==wxT("restoreok")) { wxLongLong_t process_id; Connector::restoreOk(wxString(argv[2])=="true", process_id); wxExit(); } else if (cmd == wxT("cbt-status")) { CbtStatus *s = new CbtStatus(NULL); SetTopWindow(s); s->ShowModal(); s->Destroy(); wxExit(); } #ifdef __APPLE__ else if (cmd == wxT("uninstall")) { std::string uninstaller = SBINDIR "/urbackup_uninstall"; wxExecute("/bin/sh \"" + uninstaller + "\"", wxEXEC_SYNC, NULL, NULL); wxExit(); } else if(cmd==wxT("remove_login_item")) { remove_login_item(); exit(0); } #endif #ifdef _WIN32 else if (cmd == wxT("selectWindowsComponents")) { initCom(); SelectWindowsComponents *cp = new SelectWindowsComponents(NULL); SetTopWindow(cp); cp->ShowModal(); cp->Destroy(); wxExit(); } else if (cmd == wxT("restoreWindowsComponents")) { initCom(); SelectRestoreComponents *cp = new SelectRestoreComponents(NULL); SetTopWindow(cp); cp->ShowModal(); cp->Destroy(); wxExit(); } #endif else if (cmd == wxT("info")) { Info *s = new Info(NULL); SetTopWindow(s); s->ShowModal(); s->Destroy(); wxExit(); } else if (cmd == wxT("status")) { Status *s = new Status(NULL, 0); SetTopWindow(s); s->ShowModal(); s->Destroy(); wxExit(); } else { return false; } return true; } int MyApp::OnExit() { exit(0); return 0; } MyTimer::MyTimer(void) : wxTimer(), first_status(true) { capa=INT_MAX; resetDisplayedUpdateInfo(); } wxString getStatusText(wxString status) { if(status==wxT("INCR") ) { return _("Incremental file backup running."); } else if(status==wxT("FULL") ) { return _("Full file backup running."); } else if(status==wxT("INCRI") ) { return _("Incremental image backup running."); } else if(status==wxT("FULLI") ) { return _("Full image backup running."); } else if(status==wxT("R_INCR")) { return _("Resumed incremental file backup running."); } else if(status==wxT("R_FULL")) { return _("Resumed full file backup running."); } else if (status == wxT("RESTORE_FILES")) { return _("Restoring files."); } return wxT(""); } wxString getPercentText(wxString pcdone) { wxString ret; if(!pcdone.empty()) { if(pcdone!=wxT("-1")) { ret+=getPercentDoneText(pcdone); } else { ret+=wxString(_("Indexing."))+wxT(" "); } } return ret; } namespace { wxString getIconName(ETrayIcon selicon) { switch(selicon) { case ETrayIcon_OK: return wxT("backup-ok"); case ETrayIcon_PROGRESS: return wxT("backup-progress"); case ETrayIcon_ERROR: return wxT("backup-bad"); case ETrayIcon_NO_SERVER: return wxT("backup-no-server"); case ETrayIcon_INDEXING: return wxT("backup-indexing"); case ETrayIcon_PAUSED: return wxT("backup-progress-pause"); case ETrayIcon_NO_RECENT: return wxT("backup-no-recent"); default: wxEmptyString; } return wxEmptyString; } } void MyTimer::Notify() { static SStatus status; if(!status.init || status.hasError()) { status = Connector::initStatus(status.client, first_status, 60000); first_status = false; } if(Connector::hasError() ) { if(icon_type!=ETrayIcon_ERROR) { last_status=_("Cannot connect to backup server"); icon_type=ETrayIcon_ERROR; if(tray!=NULL) tray->SetIcon(getAppIcon(getIconName(icon_type)), last_status); } status.init = false; return; } if(!status.init) { return; } if(!status.isAvailable()) { return; } status.init=false; wxStandardPathsBase& sp=wxStandardPaths::Get(); static long lastversioncheck=wxGetLocalTime(); long ct=wxGetLocalTime(); if(ct-lastversioncheck>600 && !displayed_update_info) { std::string n_version=getFile("version.txt"); std::string c_version=getFile("curr_version.txt"); if(n_version.empty())n_version="0"; if(c_version.empty())c_version="0"; if( atoi(n_version.c_str())>atoi(c_version.c_str())) { #ifndef wxUSE_TASKBARICON_BALLOONS TaskBarBaloon *tbb=new TaskBarBaloon(_("UrBackup: Update available"), _("A new version of UrBackup is available. Please click here to install it now.")); tbb->showBaloon(80000); #else tray->BalloonActionUpgrade(); tray->ShowBalloon(_("UrBackup: Update available"), _("A new version of UrBackup is available. Please click here to install it now."), 30000, wxICON_INFORMATION); displayed_update_info=true; #endif } lastversioncheck=ct; } wxString status_text; capa=status.capa; ETrayIcon last_icon_type=icon_type; bool refresh=false; if(status.status==wxT("INCR") || status.status==wxT("FULL") || status.status==wxT("INCRI") || status.status==wxT("FULLI") || status.status==wxT("R_INCR") || status.status==wxT("R_FULL")) { status_text+=getStatusText(status.status)+wxT(" "); status_text+=getPercentText(status.pcdone); icon_type=ETrayIcon_PROGRESS; backup_is_running=true; } else if(status.status==wxT("NO_RECENT")) { status_text+=wxString(_("No current backup.")) + wxT(" "); icon_type=ETrayIcon_NO_RECENT; backup_is_running=false; } else { icon_type=ETrayIcon_OK; backup_is_running=false; } if(!status.lastbackupdate.Trim().empty() ) { wxLongLong_t lastbackups; if(status.lastbackupdate.ToLongLong(&lastbackups)) { wxDateTime lastbackup_dt((wxLongLong)(lastbackups*1000)); status_text+=trans_1(_("Last backup on _1_"), lastbackup_dt.Format()); } } if(status.pause && icon_type==ETrayIcon_PROGRESS) { icon_type=ETrayIcon_PAUSED; } else if(icon_type==ETrayIcon_PROGRESS && status.pcdone==wxT("-1")) { icon_type=ETrayIcon_INDEXING; } else if( icon_type==ETrayIcon_NO_RECENT && !status.has_server ) { icon_type=ETrayIcon_NO_SERVER; } b_is_pausing=status.pause; if(icon_type!=last_icon_type || last_status!=status_text || refresh) { last_status=status_text; if(tray!=NULL) { tray->SetIcon(getAppIcon(getIconName(icon_type)), status_text); } } if(!status.new_server.empty() && tray) { #ifndef wxUSE_TASKBARICON_BALLOONS TaskBarBaloon *tbb=new TaskBarBaloon(_("UrBackup: New server"), _("A new backup server has been found. Click here to use it"), status.new_server); tbb->showBaloon(180000); #else tray->BalloonActionNewServer(status.new_server); tray->ShowBalloon(_("UrBackup: New server"), _("A new backup server has been found. Click here to use it"), 180000, wxICON_INFORMATION); #endif } if(status.ask_restore_ok>ask_restore_ok) { #ifdef __WXMAC__ bring_to_foreground(); #endif ask_restore_ok = status.ask_restore_ok; wxString ask_msg; if (status.restore_file) { ask_msg = trans_1(_("Are you sure you want to restore the file at _1_? The current file content will be overwritten by the backup file content. When in doubt please cancel and run a file backup before proceeding."), status.restore_path); } else { ask_msg = trans_1(_("Are you sure you want to restore the files in _1_? Existing files in this folder will be overwritten. Files created within the selected folder since the backup will be deleted. When in doubt please cancel and run a file backup before proceeding."), status.restore_path); } wxMessageDialog* dialog = new wxMessageDialog(NULL, ask_msg, _("UrBackup - Allow restore"), wxOK | wxCANCEL); #if !defined(__WXMAC__) && !defined(__linux__) dialog->RequestUserAttention(); #endif int rc = dialog->ShowModal(); dialog->Destroy(); if(rc == wxID_OK) { wxLongLong_t process_id = 0; Connector::restoreOk(true, process_id); if (process_id != 0) { new Status(NULL, process_id); } } else { wxLongLong_t process_id; Connector::restoreOk(false, process_id); } } #ifdef _WIN32 if(status.needs_restore_restart>needs_restore_restart) { #ifdef __WXMAC__ bring_to_foreground(); #endif needs_restore_restart = status.needs_restore_restart; wxMessageDialog* dialog = new wxMessageDialog(NULL, _("Some files could not be deleted or overwritten during the restore process. In order to overwrite/delete the files the system needs to be restarted. Do you want to do this now?"), _("UrBackup - Restart Windows"), wxOK | wxCANCEL); #if !defined(__WXMAC__) && !defined(__linux__) dialog->RequestUserAttention(); #endif if(dialog->ShowModal() == wxID_OK) { ModifyPrivilege(SE_SHUTDOWN_NAME, TRUE); ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION|SHTDN_REASON_MINOR_OTHER ); } dialog->Destroy(); } #endif } bool MyTimer::hasCapability(int capa_bit) { return MyTimer::hasCapability(capa_bit, capa); } bool MyTimer::hasCapability( int capa_bit, int capa ) { return (capa & capa_bit)>0; } void MyTimer::resetDisplayedUpdateInfo(void) { displayed_update_info=false; } #ifndef DD_RELEASE int main(int argc, char *argv[]) { wxDISABLE_DEBUG_SUPPORT(); #ifdef __APPLE__ if(argc>1 && wxString(argv[1])==wxT("daemon")) { std::cout << "Daemonizing..." << std::endl; //Daemonize. At least that works *tears* size_t pid1; if( (pid1=fork())==0 ) { setsid(); if(fork()==0) { for (int i=getdtablesize();i>=0;--i) close(i); int i=open("/dev/null",O_RDWR); dup(i); dup(i); } else { exit(0); } } else { int status; waitpid(pid1, &status, 0); exit(0); } } #endif wxEntry(argc, argv); } #else IMPLEMENT_APP(MyApp) #endif