1
0
forked from cheng/wallet
wallet/src/app.cpp
Cheng 224ab60395
layout bug due to failure to call layout.
Sqlite3 crash due to premature call to shutdown.

calls to layout very rarely have any obvious effect,
but sometimes under odd and idiosyncratic circumstances
they do.

Called shutdown after the destroy was executed, but destroy does
not immediately destroy the windows, thus does not immediately
finalize all compiled sql statements and close all database
connections. You have to wait for all the windows to be destroyed.
Again, a rare crash except under certain special circumstances.
2023-11-12 19:43:19 +10:00

203 lines
6.4 KiB
C++

#include "stdafx.h"
wxIMPLEMENT_APP(App);
App::App() : m_Config("wallet", "rho")
{
assert (singletonApp == nullptr);
singletonApp = this;
wxConfigBase::DontCreateOnDemand();
}
App::~App()
{
assert(singletonApp == this);
singletonApp = nullptr;
if (thl != nullptr)delete thl;
thl = nullptr;
}
bool App::OnInit()
{
if (wxApp::OnInit()) {
wxConfigBase* pConfig = &m_Config;
/* 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 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(wxT("%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(wxT("-"));
//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 == wxT("t")) {
m_unit_test = !arg.IsNegated();
}
else if (optionName == wxT("l")) {
m_display = !arg.IsNegated();
}
else if (optionName == wxT("d")) {
m_display |= m_display_in_front = !arg.IsNegated();
}
else if (optionName == wxT("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(wxT("OnIdle"));
wxWindow* curFocus = ::wxWindow::FindFocus();
if (curFocus != lastFocus && curFocus)
{
lastFocus = curFocus;
wxString name{ "" };
do {
name = wxString(wxT("/")) + curFocus->GetClassInfo()->GetClassName() + wxT(":") + 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 == wxT("q")) {
m_quick_unit_test = !arg.IsNegated();
m_complete_unit_test = m_complete_unit_test && !m_quick_unit_test;
}
else if (optionName == wxT("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(), wsz_error, wxICON_ERROR);
dlg.SetId(myID_ERRORMESSAGE);
dlg.ShowModal();
}
int App::OnExit()
{ if (errorCode)wxLogDebug("%s", szError);
m_Config.Flush();
sqlite3_shutdown();
return 0;
}