Commit Graph

18 Commits

Author SHA1 Message Date
a80feb708e fix(window): resize the borderless HWND directly so DPI-move sizes are exact
The hardware [WINLOG] trace showed the DPI-transition target computed correctly
(min height 720) but the window stuck ~5% larger (759), with every deferred retry
failing to shrink it. Root cause: the DX11 window is a borderless native HWND
(WS_CAPTION/WS_THICKFRAME, for native move/resize) wrapped by SDL. SDL_SetWindowSize
converts the requested CLIENT size to a window rect via AdjustWindowRectEx (adding
the caption+border frame), but our WM_NCCALCSIZE handler folds that whole frame
back into the client area — so every SDL resize inflates the window by ~one frame
(~39px height, ~16px width) and the 720 minimum becomes an unreachable 759. That,
not the earlier min-ordering/settle logic, is why the height wouldn't stay at min.

resizeWindowExact() resizes the native HWND directly via SetWindowPos on the DX11
path (window rect == client for a borderless window → exact requested size); other
platforms keep SDL_SetWindowSize. Used for the DPI-transition resize and the
deferred retry, so the window now lands on the true minimum in both directions.

Keeps the [WINLOG] native-rect + min-track tracing so the next capture confirms the
fix (or surfaces any remaining gap).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 01:08:58 -05:00
010465f835 chore(window): extend [WINLOG] with native-rect + min-track tracing
The first hardware capture showed handleDisplayScaleChange computing the correct
target (e.g. 1353x720, height = min) but the window never reaching it across all
30 deferred retries — stuck ~5% above target in BOTH DPI directions (759 vs 720
at 100%, 1136 vs 1080 at 150%). That rules out the earlier min-ordering / settle
logic and points at either the borderless WM_GETMINMAXINFO min-track
(720 * g_borderlessDpi) or a native-HWND non-client frame discrepancy on the
externally-created, SDL-wrapped DirectComposition window.

Add the data to disambiguate:
- winlogState now also logs the native GetWindowRect vs GetClientRect (+ pos),
  exposing any window-vs-client size mismatch that SDL_GetWindowSize hides.
- WM_GETMINMAXINFO logs g_borderlessDpi and the resulting min-track (once per
  change) so we can see the actual OS-enforced minimum during the transition.
- Forward-declared winlog so the WndProc can use it.

Windows-only, no behavior change. Grep the log for "[WINLOG]".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 01:05:49 -05:00
eb08b81706 chore(window): add [WINLOG] window-dimension tracing for the multi-monitor bug
Always-on stderr tracing (visible in release builds via the Windows
dragonx-debug.log redirect, unlike DRAGONX_DEBUG-gated DEBUG_LOGF) to capture
exactly how the window size / display-scale / minimum change when dragging
between monitors of different DPI. Logs:
- every WINDOW_RESIZED: size, actual vs stored scale, dpiPending/settle/retries,
  and the DPI-vs-user classification (IGNORED/RECORDED);
- every DISPLAY_SCALE_CHANGED + the full handleDisplayScaleChange trace
  (saved-under-old-scale, restore/proportional, min-clamp, display-clamp, the
  SetWindowMinimumSize+SetWindowSize, and the resulting window state);
- each deferred-resize retry;
- monitor crossings (WINDOW_MOVED, throttled to display changes);
- startup and shutdown size.

Low volume — only fires on window events. Temporary diagnostic; remove once the
multi-monitor sizing bug is fixed. Grep the log for "[WINLOG]".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 00:49:59 -05:00
8cbd0cab9d fix(window): preserve the exact minimum height across monitor DPI moves
Moving the window between monitors of different scaling (150% -> 100% -> 150%)
left the height off the minimum in BOTH directions, forcing a manual resize each
time. A deep trace against the vendored SDL3 source found two distinct causes:

- Shrink leg (higher -> lower scale): handleDisplayScaleChange called
  SDL_SetWindowSize BEFORE SDL_SetWindowMinimumSize. SDL clamps a size request up
  to the current minimum (SDL_video.c:3184-3191), so the smaller target was
  clamped back to the stale larger min; SetWindowMinimumSize only grows a window,
  never shrinks it, so lowering the min afterwards didn't pull it back. The
  deferred retry masked it only on rendered frames, so it leaked when the app was
  idle. Fix: set the new minimum BEFORE resizing.

- Return leg (lower -> higher scale): the single-shot dpiResizePending flag let a
  later settling WINDOW_RESIZED in the same burst be misclassified as a user
  resize and recorded, corrupting savedSizeForScale for that scale so the
  remembered min was lost. Fix: a frame-counted settle window (dpiSettleFrames)
  suppresses resize-recording for the whole transition burst regardless of event
  ordering; also clamp any restored/scaled size up to the new scale's minimum.

Only user resizes outside the ~40-frame settle burst are recorded, so normal
resizing is unaffected. SDL clamp semantics verified in-repo; build clean. The
transition needs real multi-monitor hardware to exercise end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:58:05 -05:00
a9f0d544cc fix(window): clamp the restored window size to the display on every startup
The only startup clamp to the display's usable bounds lived inside the
`currentDpiScale > 1.01f` HiDPI branch, so on a standard-DPI (100%) cold start it
never ran. A window size saved on a larger or since-disconnected monitor then
opened oversized / partly off-screen (title bar under the taskbar), since the
window is also re-centered at the saved size.

Hoist the clamp-to-usable-bounds + re-center out of the HiDPI branch so it runs
on every startup; the DPI multiply and scaled minimum-size stay HiDPI-only. It
resizes only when the clamp actually changes the size, so a window that fits its
display is left untouched — only genuinely-oversized ones clamp. Also log when a
persisted size is rejected on load/save (below the 1024x720 floor) so "my window
keeps resetting" reports become traceable.

Root-caused via a multi-agent audit of the window-size/DPI logic, which also
confirmed the save/restore DPI round-trip is otherwise correct (the restore-side
auto-scale multiply was mistaken by the investigators for a unit bug). Verified:
a 9999x9999 saved size now clamps to the display at scale 1.00 (previously the
clamp was skipped on a same-DPI cold start).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:23:39 -05:00
a86cb8f0f3 feat(debug): full UI screenshot sweep — captures modals/dialogs/flows/states
The existing sweep only captures tabs. This adds a "Full UI sweep" (DEBUG
OPTIONS) that also drives every normally-hidden surface into view and captures
it under every skin, so all the UI a normal sweep misses can be reviewed at
once.

- The capture unit becomes a "surface" (SweepTarget: a base tab, optionally
  with a setup()/teardown() that forces a modal / multi-step flow / state
  overlay on top). Tabs are surfaces with a null setup. The existing tab sweep
  is folded into the same state machine (one code path). All sweep logic +
  the catalog + demo data move into a new src/app_sweep.cpp.
- Runs OFFLINE against injected demo data (installDemoWalletData snapshots then
  restores the real state_ — WalletState isn't copy-assignable, so a targeted
  field snapshot is used) and fires NO live op: capture_mode_ guards the
  seed-backup RPC, auto-lock, and the migration pumps; the async-firing dialogs
  are neutralized by pre-setting their state (fetch_started_ + demo phrase;
  seed_migration_step_ set directly). Verified: 0 RPC/secret/send calls.
- Catalog (v1): tabs + the bool-flag modals (import/export key, backup,
  seed-backup, about, settings) + the 6 migrate-to-seed steps + 4 wizard steps
  + lock/warmup/not-ready overlays + the send-confirm popup (via a new
  ui::SweepShowSendConfirm debug hook, since its state is send_tab-static).
- Overlay/blur surfaces settle 8 frames (blur backdrop freeze); setup re-runs
  each frame (OpenPopup popups must re-fire). updateScreenshotSweep now runs
  before the first-run-wizard early-return in render() so the sweep advances
  while a wizard step is shown. main.cpp drops vsync during a sweep so it isn't
  throttled to the compositor's unfocused rate. Output:
  <config>/screenshots-full/<surface>/<skin>.png + index.md.
- DRAGONX_FULL_SWEEP=1 runs the sweep headlessly then quits (CI / verification).

Verified end-to-end under WSLg: 288 PNGs (9 skins x 32 surfaces), all 1200x720,
[Sweep] done, clean quit, no daemon. Byte-identity across runs holds only for
static skins on data-free surfaces — the rest vary by animated theme effects /
live price / relative timestamps (expected for a review tool, not a bug).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:57:54 -05:00
7ee20bb497 fix(wallet): connect the isolated seed node over plaintext RPC + add smoke
The seed-wallet creator forced TLS on its RPC client, but the DRAGONX RPC is
plaintext HTTP on localhost (-tls=only applies to P2P, not the RPC; the main
GUI's conf has no rpctls key and connects over http too). Forcing https made
every connect fail with "SSL connect error", so the isolated create never
completed. Connect without TLS, matching the main daemon path.

Also add an env-gated (DRAGONX_SEED_CREATE_SMOKE=1) headless smoke in main()
that runs SeedWalletCreator::create() before GUI init and prints
ok/word-count/address (never the seed words) — used to validate the full C++
creator path without the GUI. Harmless in normal runs.

Validated end-to-end against the hd-transparent-keys (v1.0.3-dc45e7d9)
daemon: ok=1, words=24, a shielded z-address returned, temp datadir cleaned up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 14:17:00 -05:00
dddf1b6ec7 feat(debug): theme x tab screenshot sweep + Debug options dialog
Add a debug tool that cycles every skin across every build-enabled tab and saves a
PNG of each to a timestamped folder under the config dir (screenshots/sweep_<ts>/)
— for gathering visual context on theme-specific UI work.

- App state machine (app_network.cpp): startScreenshotSweep() builds the
  skin+enabled-page lists, saves the current skin/page, and steps through them;
  updateScreenshotSweep() (top of App::render) pins the page + settles ~4 frames
  after each skin/page change (skin switches reload TOML + reset the acrylic
  capture, so they need to settle); wantsScreenshotThisFrame()/screenshotSweepPath()
  /onScreenshotCaptured() coordinate with main.cpp. Restores the original skin/page
  when done; nothing persisted.
- Framebuffer capture (main.cpp): read the finished frame and encode PNG via the
  bundled miniz (tdefl_write_image_to_png_file_in_memory_ex). GL reads FBO 0 (RGBA,
  bottom-up -> flip); DX11 copies the backbuffer to a staging texture + maps it
  (BGRA, top-down -> channel-swap). Alpha forced opaque.
- Settings UI: move the Verbose logging checkbox off the wallet row into a new
  "Debug options" button that opens a dialog housing the verbose toggle + a "Run
  screenshot sweep" button. New i18n keys.

Both platforms build; no-crash smoke verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 17:41:49 -05:00
af2db4366c refactor(audit): de-duplicate the main.cpp backdrop draw + DPI transition
Two render-loop de-duplications, zero behavior change (verified byte-equivalent
on both the GL and DX11 backends via the mingw Windows cross-build):

- drawWindowBackdrop(app, bgDL, p0, p1, backdrop_active, lowSpec): the ~80-line
  gradient/texture/acrylic-capture/WindowBg-alpha block was copy-pasted in the
  main loop (with low-spec guards) and the resize-watcher lambda (without them).
  Extracted once; the main loop calls it with lowSpec=isLowSpecMode() and the
  resize watcher with lowSpec=false — each reproducing its CURRENT behavior
  exactly (pure dedup, no change). The intentional differences around it
  (resize's immediate present(0) vs the main loop's vsync, the main loop's
  try/catch, the BeginFrame low-spec guard) are left untouched.

- handleDisplayScaleChange(window, newScale, savedSizeForScale, lastKnownW/H,
  dpiTargetW/H, dpiResizeRetries, dpiResizePending): the SDL display-scale-change
  handler was duplicated ~verbatim in the idle-wait and poll event paths
  (differing only in debug-log text). Moved the body into one helper called from
  both; the #ifdef DRAGONX_USE_DX11 g_borderlessDpi and #ifdef __APPLE__ scale
  normalization are preserved.

Deliberately did NOT unify the full frame/present sequence — the resize path's
immediate present and lack of try/catch are intentional.

Full-node (GL) + Lite build clean; Windows/DX11 cross-build compiles main.cpp
clean; ctest 1/1; hygiene clean. NEEDS RUNTIME VERIFICATION: a live window
drag-resize (backdrop draws, no flicker) and a monitor DPI-scale change (window
resizes + fonts reload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 21:00:40 -05:00
975743f754 feat(wallet): persist history and surface pending sends
Add an encrypted SQLite transaction history cache with cached tip metadata and
per-address shielded scan progress so startup and full refreshes avoid
re-scanning every z-address while still invalidating on wallet/address/rescan
changes.

Improve wallet history loading by paging transparent transactions, preserving
cached shielded and sent rows, keeping recent/unconfirmed activity visible, and
classifying mining-address receives. Show z_sendmany opid sends immediately in
History and Overview, pin pending rows through refreshes, and apply optimistic
address/balance debits until opids resolve.

Add timestamped RPC console tracing by source/method without logging params or
results, reduce redundant refresh/RPC calls, and cache Explorer recent block
summaries in SQLite.

Expand focused tests for transaction cache encryption, scan-progress
persistence/invalidation, history preservation, operation-status parsing,
pending send visibility, and Explorer/RPC refresh behavior.
2026-05-05 03:22:14 -05:00
2b3277529e macOS port: build, rendering, daemon, and mining fixes
Build & setup:
- Fix setup.sh and build.sh for macOS (bundle daemon, xmrig, sapling params, asmap.dat into .app)
- Fix CMakeLists.txt libsodium linking for macOS
- Fix incbin.h to use __DATA,__const section on macOS
- Remove vendored libsodium-1.0.18 source tree (use fetch script instead)
- Remove prebuilt-binaries/xmrig (replaced by xmrig-hac)
- Add .DS_Store to .gitignore

Rendering & UI:
- Use GLSL #version 150 and OpenGL 3.2 Core Profile on macOS
- Force dpiScale=1.0 on macOS to fix Retina double-scaling
- Set default window/UI opacity to 100% on Mac/Linux
- Add scroll fade shader guard for macOS GL compatibility
- Add ImGui error recovery around render loop and mining tab

Daemon & bootstrap:
- Fix getDragonXDataDir() to return ~/Library/Application Support/Hush/DRAGONX/ on macOS
- Fix isPortInUse() with connect() fallback (no /proc/net/tcp on macOS)
- Increase daemon watchdog timeout from 3s to 15s
- Add daemon status indicator (colored dot + label) in wizard bootstrap phases

Mining tab:
- Fix EmbeddedDaemon::getMemoryUsageMB() crash on macOS (was using Linux /proc)
- Fix XmrigManager::getMemoryUsageMB() to use ps on macOS instead of /proc
- Restructure RenderMiningTab with wrapper pattern for exception safety
- Fix default pool URL to include port (pool.dragonx.is:3433)
2026-03-19 14:26:04 -05:00
40dd6d45b2 daemon version check, idle mining control, bootstrap mirror, import key paste, and cleanup
- Add startup binary version checking for dragonxd/xmrig
- Display daemon version in UI
- Add idle mining thread count adjustment
- Add bootstrap mirror option (bootstrap2.dragonx.is) in setup wizard
- Add paste button to import private key dialog with address validation
- Add z-address generation UI feedback (loading indicator)
- Add option to delete blockchain data while preserving wallet.dat
- Add font scale slider hotkey tooltip (Ctrl+Plus/Ctrl+Minus)
- Fix Windows RPC auth: trim \r from config values, add .cookie fallback
- Fix connection status message during block index loading
- Improve application shutdown to prevent lingering background process
2026-03-17 14:57:12 -05:00
d7bc5c638a fix: remove D3D11 debug layer flag that prevented startup on user machines
DRAGONX_DEBUG was defined unconditionally, causing D3D11CreateDevice() to
request the debug layer via D3D11_CREATE_DEVICE_DEBUG. This layer is only
available on machines with the Windows SDK or Graphics Tools installed,
so the call fails with DXGI_ERROR_SDK_COMPONENT_MISSING on regular user
machines — causing the app to silently exit.
2026-03-12 00:13:27 -05:00
b3a0ce29ed 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
2026-03-05 22:43:27 -06:00
eda19ef6d5 improved font scaling text and window adjustment, added ctrl + scroll hotkey for font scaling 2026-03-05 01:22:20 -06:00
f5378a55ed UX improvements 2026-02-28 00:58:43 -06:00
eebfd5947e console and mining tab visual improvements 2026-02-27 13:30:06 -06:00
3aee55b49c ObsidianDragon - DragonX ImGui Wallet
Full-node GUI wallet for DragonX cryptocurrency.
Built with Dear ImGui, SDL3, and OpenGL3/DX11.

Features:
- Send/receive shielded and transparent transactions
- Autoshield with merged transaction display
- Built-in CPU mining (xmrig)
- Peer management and network monitoring
- Wallet encryption with PIN lock
- QR code generation for receive addresses
- Transaction history with pagination
- Console for direct RPC commands
- Cross-platform (Linux, Windows)
2026-02-27 00:26:01 -06:00