fix: Windows identity, async address creation, mining UI, and chart artifacts

Windows identity:
- Add VERSIONINFO resource (.rc) with ObsidianDragon file description
- Embed application manifest for DPI awareness and shell identity
- Patch libwinpthread/libpthread to remove competing VERSIONINFO
- Set AppUserModelID and HWND property store to override Task Manager cache
- Link patched pthread libs to eliminate "POSIX WinThreads" description

Address creation (+New button):
- Move z_getnewaddress/getnewaddress off UI thread to async worker
- Inject new address into state immediately for instant UI selection
- Trigger background refresh for balance updates

Mining tab:
- Add pool mining dropdown with saved URLs/workers and bookmarks
- Add solo mining log panel from daemon output with chart/log toggle
- Fix toggle button cursor (render after InputTextMultiline)
- Auto-restart miner on pool config change
- Migrate default pool URL to include stratum port

Transactions:
- Sort pending (0-conf) transactions to top of history
- Fall back to timereceived when timestamp is missing

Shutdown:
- Replace blocking sleep_for calls with 100ms polling loops
- Check shutting_down_ flag throughout daemon restart/bootstrap flows
- Reduce daemon stop timeout from 30s to 10s

Other:
- Fix market chart fill artifact (single concave polygon vs per-segment quads)
- Add bootstrap checksum verification state display
- Rename daemon client identifier to ObsidianDragon
This commit is contained in:
2026-03-05 22:43:27 -06:00
parent e2265b0bdf
commit b3a0ce29ed
20 changed files with 842 additions and 116 deletions

View File

@@ -46,6 +46,15 @@
#include "platform/windows_backdrop.h"
#include <windows.h>
#include <dwmapi.h>
#include <shlobj.h>
#include <propkey.h>
#include <propsys.h>
// SetCurrentProcessExplicitAppUserModelID lives behind NTDDI_WIN7 in
// MinGW's shobjidl.h. Rather than forcing the version macro globally,
// declare just the one function we need (available on Windows 7+).
extern "C" HRESULT __stdcall SetCurrentProcessExplicitAppUserModelID(PCWSTR AppID);
// SHGetPropertyStoreForWindow is also behind NTDDI_WIN7 in MinGW headers.
extern "C" HRESULT __stdcall SHGetPropertyStoreForWindow(HWND hwnd, REFIID riid, void** ppv);
// Not defined in older MinGW SDK headers
#ifndef WS_EX_NOREDIRECTIONBITMAP
#define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
@@ -107,6 +116,45 @@ static LONG WINAPI CrashHandler(EXCEPTION_POINTERS* ep)
} catch (...) {}
return EXCEPTION_EXECUTE_HANDLER;
}
// Set the window's shell property store so Task Manager, taskbar, and shell
// always show "ObsidianDragon" regardless of any cached VERSIONINFO metadata.
static void SetWindowIdentity(HWND hwnd)
{
IPropertyStore* pps = nullptr;
HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_IPropertyStore, (void**)&pps);
if (SUCCEEDED(hr) && pps) {
// Set AppUserModel.ID on the window (overrides process-level ID for this window)
PROPVARIANT pvId;
PropVariantInit(&pvId);
pvId.vt = VT_LPWSTR;
pvId.pwszVal = const_cast<LPWSTR>(L"DragonX.ObsidianDragon.Wallet");
pps->SetValue(PKEY_AppUserModel_ID, pvId);
// Don't PropVariantClear — the string is a static literal
// Set RelaunchDisplayNameResource so the shell shows our name
PROPVARIANT pvName;
PropVariantInit(&pvName);
pvName.vt = VT_LPWSTR;
pvName.pwszVal = const_cast<LPWSTR>(L"ObsidianDragon");
pps->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, pvName);
// Set RelaunchCommand (required alongside RelaunchDisplayNameResource)
PROPVARIANT pvCmd;
PropVariantInit(&pvCmd);
pvCmd.vt = VT_LPWSTR;
wchar_t exePath[MAX_PATH] = {};
GetModuleFileNameW(nullptr, exePath, MAX_PATH);
pvCmd.pwszVal = exePath;
pps->SetValue(PKEY_AppUserModel_RelaunchCommand, pvCmd);
pps->Commit();
pps->Release();
DEBUG_LOGF("Window property store: identity set to ObsidianDragon\n");
} else {
DEBUG_LOGF("SHGetPropertyStoreForWindow failed: 0x%08lx\n", (unsigned long)hr);
}
}
#endif
// ---------------------------------------------------------------
@@ -353,6 +401,11 @@ int main(int argc, char* argv[])
}
// Install crash handler for diagnostics
SetUnhandledExceptionFilter(CrashHandler);
// Set the Application User Model ID so Windows Task Manager, taskbar,
// and jump lists show "ObsidianDragon" instead of inheriting a
// description from the MinGW runtime ("POSIX WinThreads for Windows").
SetCurrentProcessExplicitAppUserModelID(L"DragonX.ObsidianDragon.Wallet");
#endif
// Check for payment URI in command line
@@ -499,6 +552,10 @@ int main(int argc, char* argv[])
UpdateWindow(nativeHwnd);
DEBUG_LOGF("Borderless window: native title bar removed\n");
// Set shell property store on the HWND so Task Manager and the taskbar
// always show "ObsidianDragon" (overrides any cached metadata).
SetWindowIdentity(nativeHwnd);
// Initialize DirectX 11 context with DXGI alpha swap chain
dragonx::platform::DX11Context dx;
if (!dx.init(window)) {
@@ -1719,6 +1776,10 @@ int main(int argc, char* argv[])
}
}
// Hide the window immediately so the user perceives the app as closed
// while background cleanup (thread joins, RPC disconnect) continues.
SDL_HideWindow(window);
// Final cleanup (daemon already stopped by beginShutdown)
app.shutdown();
#ifdef DRAGONX_USE_DX11
@@ -1727,6 +1788,20 @@ int main(int argc, char* argv[])
Shutdown(window, gl_context);
#endif
// Explicitly release the single-instance lock before exit so a new
// instance can start immediately.
g_single_instance.unlock();
// Force-terminate the process. All important cleanup (daemon stop,
// settings save, RPC disconnect, SDL teardown) has completed above.
// On Windows with mingw-w64 POSIX threads, normal CRT cleanup
// deadlocks waiting for detached pthreads. On Linux, static
// destructors and atexit handlers can also block. _Exit() bypasses
// all of that.
fflush(stdout);
fflush(stderr);
_Exit(0);
return 0;
}