207 lines
6.6 KiB
C++
207 lines
6.6 KiB
C++
|
#include "stdafx.h"
|
|||
|
|
|||
|
thread_local thread_local__* thl{ nullptr };
|
|||
|
wxIMPLEMENT_APP(App);
|
|||
|
|
|||
|
App::App()
|
|||
|
{
|
|||
|
assert (singletonApp == nullptr);
|
|||
|
singletonApp = this;
|
|||
|
if (thl == nullptr)thl = new thread_local__();
|
|||
|
}
|
|||
|
|
|||
|
App::~App()
|
|||
|
{
|
|||
|
assert(singletonApp == this);
|
|||
|
singletonApp = nullptr;
|
|||
|
if (thl != nullptr)delete thl;
|
|||
|
thl = nullptr;
|
|||
|
}
|
|||
|
|
|||
|
bool App::OnInit()
|
|||
|
{ if (wxApp::OnInit()) {
|
|||
|
SetVendorName(_T("rho")); /* This causes the non volatile config data to be stored under the rho on
|
|||
|
windows.*/
|
|||
|
SetAppName(_T("wallet")); /* This causes the non volatile config data to be stored under rho\wallet
|
|||
|
We will generally place data in the database, and if additional executables need their own data
|
|||
|
in the config, they will create their own subkey under Computer\HKEY_CURRENT_USER\Software\rho */
|
|||
|
pConfig = std::unique_ptr<wxConfigBase>(wxConfigBase::Get());
|
|||
|
pConfig->SetRecordDefaults(false);
|
|||
|
/* pConfig corresponds to the Windows Registry entry
|
|||
|
Computer\HKEY_CURRENT_USER\Software\rho\wallet
|
|||
|
|
|||
|
Contrary to wxWidgets documentation, the config data on windows is by default stored in
|
|||
|
HKCU, HKEY_CURRENT_USER, not in HKLM, HKEY_LOCAL_MACHINE.
|
|||
|
|
|||
|
We probably should have placed per user data in an sqlite3 file in
|
|||
|
wxStandardPaths::GetUserDataDir()
|
|||
|
|
|||
|
Data global to all users has to go in an sqlite3 file in wxStandardPaths::GetAppDocumentsDir()
|
|||
|
or wxStandardPaths::GetLocalDataDir()
|
|||
|
|
|||
|
User local database will record the derivation of all secrets, and what wallets along the path
|
|||
|
are logged in. The local machine database will hold the global consensus blockchain, which contains
|
|||
|
no privacy sensitive information, and will also hold data global to all users on a particular
|
|||
|
machine.
|
|||
|
|
|||
|
A wallet's secret can be stored in a file - we will eventually provide passwords for files,
|
|||
|
but passwords provide a false sense of security, because if someone gets a copy of that file,
|
|||
|
a sophisticated attacker can perform an offline brute force attack, thus a human memorable
|
|||
|
password only provides protection against casual and opportunistic attackers.
|
|||
|
If the file is insecure, password needs to impossible to remember, and stored somewhere secure..*/
|
|||
|
|
|||
|
Frame* frame = new Frame(pConfig->GetAppName());
|
|||
|
frame->Show(true); //Frame, being top level unowned window, is owned by the one and only message pump
|
|||
|
if (m_display_in_front && singletonFrame != nullptr && singletonFrame->m_pLogWindow != nullptr) singletonFrame->m_pLogWindow->GetFrame()->Raise();
|
|||
|
return true;
|
|||
|
}
|
|||
|
else return false;
|
|||
|
}
|
|||
|
|
|||
|
int App::OnRun()
|
|||
|
{
|
|||
|
Bind(wxEVT_MENU, &App::OnError, this, myID_ERRORMESSAGE);
|
|||
|
int exitcode = wxApp::OnRun();
|
|||
|
//wxTheClipboard->Flush();
|
|||
|
return exitcode ? exitcode : errorCode;
|
|||
|
}
|
|||
|
|
|||
|
bool App::OnExceptionInMainLoop()
|
|||
|
{
|
|||
|
bool handled{ false };
|
|||
|
wxString error;
|
|||
|
try {
|
|||
|
throw; // Rethrow the current exception.
|
|||
|
}
|
|||
|
catch (const FatalException& e) {
|
|||
|
error = wsz_program + _wx(e.what());
|
|||
|
if (!errorCode)errorCode = 10;
|
|||
|
}
|
|||
|
catch (const MyException& e) {
|
|||
|
// If we handle an error at this level, the current action has been abruptly terminated,
|
|||
|
// and we need to inform the user, but we are not going to terminate the program,
|
|||
|
// nor set an error number for exit.
|
|||
|
handled = true;
|
|||
|
error = wsz_operation + _wx(e.what());
|
|||
|
}
|
|||
|
catch (const std::exception& e) {
|
|||
|
error = wsz_program + _wx(e.what());
|
|||
|
errorCode = 9;
|
|||
|
}
|
|||
|
catch (...) {
|
|||
|
error = wsz_program + _wx(sz_unknown_error);
|
|||
|
errorCode = 8;
|
|||
|
}
|
|||
|
wxLogError(_T("%s"), error);
|
|||
|
wxMessageDialog dlg(singletonFrame, error, wsz_error, wxICON_ERROR);
|
|||
|
dlg.SetId(myID_ERRORMESSAGE);
|
|||
|
dlg.ShowModal();
|
|||
|
// returning false to exit the main loop and thus terminate the program.
|
|||
|
return handled;
|
|||
|
}
|
|||
|
|
|||
|
void App::OnInitCmdLine(wxCmdLineParser& parser)
|
|||
|
{
|
|||
|
parser.SetDesc(g_cmdLineDesc);
|
|||
|
// must refuse '/' as parameter starter or cannot use "/path" style paths
|
|||
|
parser.SetSwitchChars(_T("-"));
|
|||
|
//Command line parameters
|
|||
|
parser.SetLogo(wsz_commandLineLogo);
|
|||
|
parser.AddUsageText(wsz_usageText);
|
|||
|
}
|
|||
|
|
|||
|
bool App::OnCmdLineParsed(wxCmdLineParser& parser)
|
|||
|
{
|
|||
|
for (const auto& arg : parser.GetArguments()) {
|
|||
|
wxString optionName;
|
|||
|
switch (arg.GetKind())
|
|||
|
{
|
|||
|
case wxCMD_LINE_SWITCH:
|
|||
|
optionName = arg.GetShortName();
|
|||
|
if (optionName == _T("t")) {
|
|||
|
m_unit_test = !arg.IsNegated();
|
|||
|
}
|
|||
|
else if (optionName == _T("l")) {
|
|||
|
m_display = !arg.IsNegated();
|
|||
|
}
|
|||
|
else if (optionName == _T("d")) {
|
|||
|
m_display |= m_display_in_front = !arg.IsNegated();
|
|||
|
}
|
|||
|
else if (optionName == _T("f")) {
|
|||
|
m_log_focus_events = !arg.IsNegated();
|
|||
|
if (m_log_focus_events) {
|
|||
|
Bind(
|
|||
|
wxEVT_IDLE,
|
|||
|
+[](wxIdleEvent& event) { //Since this function is only ever used once, never being unbound, using a lambda to avoid naming it.
|
|||
|
static wxWindow* lastFocus = (wxWindow*)NULL;
|
|||
|
//wxLogMessage(_T("OnIdle"));
|
|||
|
wxWindow* curFocus = ::wxWindow::FindFocus();
|
|||
|
if (curFocus != lastFocus && curFocus)
|
|||
|
{
|
|||
|
lastFocus = curFocus;
|
|||
|
wxString name{ "" };
|
|||
|
do {
|
|||
|
name = wxString(_T("/")) + curFocus->GetClassInfo()->GetClassName() + _T(":") + curFocus->GetName() + name;
|
|||
|
} while (curFocus = curFocus->GetParent());
|
|||
|
wxLogMessage(name);
|
|||
|
}
|
|||
|
event.Skip(); //Called so we can bind multiple tasks to idle, and they will all be handled.
|
|||
|
}
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (optionName == _T("q")) {
|
|||
|
m_quick_unit_test = !arg.IsNegated();
|
|||
|
m_complete_unit_test = m_complete_unit_test && !m_quick_unit_test;
|
|||
|
}
|
|||
|
else if (optionName == _T("c")) {
|
|||
|
m_complete_unit_test = !arg.IsNegated();
|
|||
|
m_quick_unit_test = m_quick_unit_test && !m_complete_unit_test;
|
|||
|
}
|
|||
|
break;
|
|||
|
case wxCMD_LINE_OPTION:
|
|||
|
assert(false);
|
|||
|
/* switch (arg.GetType()) {
|
|||
|
case wxCMD_LINE_VAL_NUMBER:
|
|||
|
// do something with itarg->GetLongVal();
|
|||
|
break;
|
|||
|
case wxCMD_LINE_VAL_DOUBLE:
|
|||
|
// do something with itarg->GetDoubleVal();
|
|||
|
break;
|
|||
|
case wxCMD_LINE_VAL_DATE:
|
|||
|
// do something with itarg->GetDateVal();
|
|||
|
break;
|
|||
|
case wxCMD_LINE_VAL_STRING:
|
|||
|
// do something with itarg->GetStrVal();
|
|||
|
break;
|
|||
|
}*/
|
|||
|
break;
|
|||
|
case wxCMD_LINE_PARAM:
|
|||
|
m_params.push_back(arg.GetStrVal());
|
|||
|
// This intended to support subcommand processing, but not handling subcommands yet
|
|||
|
// g_cmdLineDesc has been set to disallow multiple arguments.
|
|||
|
break;
|
|||
|
default:
|
|||
|
assert(0);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
void App::OnError(wxCommandEvent& event)
|
|||
|
{
|
|||
|
// We use this to display errors where throwing would cause problems, as in a destructor
|
|||
|
// Instead we post an event to be handled in due course.
|
|||
|
wxMessageDialog dlg(singletonFrame, event.GetString(), _T("Error"), wxICON_ERROR);
|
|||
|
dlg.SetId(myID_ERRORMESSAGE);
|
|||
|
dlg.ShowModal();
|
|||
|
}
|
|||
|
|
|||
|
int App::OnExit()
|
|||
|
{
|
|||
|
assert(pConfig.get());
|
|||
|
if (errorCode)wxLogDebug("%s", szError);
|
|||
|
return 0;
|
|||
|
}
|