-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAeonMain.cpp
More file actions
523 lines (456 loc) · 21.9 KB
/
AeonMain.cpp
File metadata and controls
523 lines (456 loc) · 21.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
// AeonBrowser — AeonMain.cpp
// DelgadoLogic
//
// Main entry point — Win32 WinMain.
// Uses AeonProbe::RunProbe() for tier detection, TierDispatcher_LoadEngine() for
// engine DLL loading, and AeonBridge::Init() for JS↔C++ communication.
//
// Session 19: Added CrashHandler, TLS init, SessionManager, PulseBridge phases.
// Fixed OnCrash/OnNewTab callbacks to actually modify UI state.
// Added __cdecl calling convention for ABI compliance.
#include <windows.h>
#include <windowsx.h>
#include <dwmapi.h>
#include <shlobj.h>
#include <cstdio>
#pragma comment(lib, "dwmapi.lib")
#include "core/AeonVersion.h"
#include "core/probe/HardwareProbe.h"
#include "core/engine/AeonEngine_Interface.h"
#include "core/engine/AeonBridge.h"
#include "core/ui/BrowserChrome.h"
#include "core/network/NetworkSentinel.h"
#include "core/settings/SettingsEngine.h"
#include "core/memory/TabSleepManager.h"
#include "core/security/PasswordVault.h"
#include "core/crash/CrashHandler.h"
#include "core/crash/CrashKeys.h"
#include "core/crash/Breadcrumbs.h"
#include "core/crash/AeonLog.h"
#include "core/tls/TlsAbstraction.h"
#include "core/session/SessionManager.h"
#include "telemetry/PulseBridge.h"
#include "updater/AutoUpdater.h"
#include "core/billing/OmniLicense.h"
#include "core/history/HistoryEngine.h"
#include "core/download/DownloadManager.h"
#include "core/agent/AeonAgentPipe.h"
#include "ai/aeon_tab_intelligence.h"
#include "ai/aeon_journey_analytics.h"
#define AEON_WINDOW_CLASS L"AeonBrowserHost"
#define AEON_TITLE L"Aeon Browser \u2014 by DelgadoLogic"
// Forward declarations
LRESULT CALLBACK AeonWndProc(HWND, UINT, WPARAM, LPARAM);
// Global engine pointer — shared between AeonMain and WndProc.
// BrowserChrome owns GWLP_USERDATA for its ChromeState, so we use a global.
static AeonEngineVTable* g_Engine = nullptr;
// Global main window handle — used by engine callbacks to push events
// into BrowserChrome's tab state via the public API.
static HWND g_MainHwnd = nullptr;
// Global AI engine pointers — initialized during boot, non-owning refs
static AeonTabIntelligence* g_TabIntel = nullptr;
static AeonJourneyAnalytics* g_JourneyAI = nullptr;
// Declared in TierDispatcher.cpp — loads the engine DLL chain
AeonEngineVTable* TierDispatcher_LoadEngine(const SystemProfile* profile);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nShowCmd) {
// PHASE 0: Install crash handler FIRST — catches any init failures.
AeonCrash::Install();
AeonCrash::SetKey("boot_phase", "init");
AeonCrash::SetKey("version", AEON_VERSION);
AeonCrash::AddBreadcrumb("boot", "crash_handler_installed");
// Console logging for diagnostics — attach console when --debug flag is passed.
// Release builds use the internal logging subsystem (HistoryEngine trace log).
{
bool wantConsole = false;
for (int i = 1; i < __argc; ++i) {
if (strcmp(__argv[i], "--debug") == 0) { wantConsole = true; break; }
}
if (wantConsole) {
AllocConsole();
FILE* _f = nullptr;
freopen_s(&_f, "CONOUT$", "w", stdout);
freopen_s(&_f, "CONOUT$", "w", stderr);
fprintf(stdout, "[Aeon] Debug console attached.\n");
}
}
// Initialize structured logger — after console, before anything else
AeonLog::Init();
AeonCrash::AddBreadcrumb("boot", "logger_initialized");
fprintf(stdout, "\n");
fprintf(stdout, "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n");
fprintf(stdout, "\u2551 Aeon Browser \u2014 by DelgadoLogic \u2551\n");
fprintf(stdout, "\u2551 browseaeon.com \u2551\n");
fprintf(stdout, "\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n");
// PHASE 1: Hardware probe — detect OS tier + CPU
AeonCrash::SetKey("boot_phase", "hardware_probe");
SystemProfile profile = {};
AeonTier tier = AeonProbe::RunProbe(profile);
ALOG_INFO("Boot", "Aeon Browser v%s starting...", AEON_VERSION);
ALOG_INFO("Boot", "Tier: %s | OS: %u.%u.%u | Cores: %d | RAM: %.0f MB",
AeonProbe::TierName(tier),
profile.osMajor, profile.osMinor, profile.osBuild,
(int)profile.cpu.cores,
(double)profile.ramBytes / (1024.0 * 1024.0));
AeonCrash::SetKey("tier", AeonProbe::TierName(tier));
AeonCrash::SetKeyInt("ram_mb", (int64_t)(profile.ramBytes / (1024 * 1024)));
AeonCrash::AddBreadcrumb("boot", "hardware_probe_complete");
// PHASE 1b: TLS stack — must be initialised before ANY network call.
if (!AeonTls::Initialize(profile)) {
fprintf(stderr, "[Boot] WARNING: TLS init failed — network features may not work.\n");
}
// PHASE 1c: Session manager — restore previous tabs on crash/restart.
SessionManager::Initialize(profile);
// PHASE 1d: Telemetry baseline ping + crash upload from previous session
AeonCrash::SetKey("boot_phase", "telemetry");
PulseBridge::SendStartupPing(profile);
PulseBridge::UploadPendingCrash();
AeonCrash::AddBreadcrumb("boot", "telemetry_initialized");
// OmniLicense Hardware Check
fprintf(stdout, "[Boot] Evaluating Crypto Signature via OmniLicense...\n");
std::string hwid = OmniLicense::GenerateHWID();
fprintf(stdout, "[Boot] OmniLicense HWID: %s\n", hwid.c_str());
// 2. Load settings
AeonSettings settings = SettingsEngine::Load();
// 3. Initialize Password Vault
char appData[MAX_PATH] = {};
SHGetFolderPathA(nullptr, CSIDL_APPDATA, nullptr, 0, appData);
// Create parent dir %APPDATA%\DelgadoLogic first
char dlDir[MAX_PATH];
_snprintf_s(dlDir, sizeof(dlDir), _TRUNCATE, "%s\\DelgadoLogic", appData);
if (!CreateDirectoryA(dlDir, nullptr) && GetLastError() != ERROR_ALREADY_EXISTS) {
fprintf(stderr, "[Boot] WARNING: Cannot create %s: %lu\n", dlDir, GetLastError());
}
// Then create %APPDATA%\DelgadoLogic\Aeon
char vaultDir[MAX_PATH];
_snprintf_s(vaultDir, sizeof(vaultDir), _TRUNCATE, "%s\\Aeon", dlDir);
if (!CreateDirectoryA(vaultDir, nullptr) && GetLastError() != ERROR_ALREADY_EXISTS) {
fprintf(stderr, "[Boot] WARNING: Cannot create %s: %lu\n", vaultDir, GetLastError());
}
char vaultPath[MAX_PATH];
_snprintf_s(vaultPath, sizeof(vaultPath), _TRUNCATE, "%s\\vault.db", vaultDir);
if (!PasswordVault::Init(vaultPath)) {
fprintf(stderr, "[Boot] WARNING: Vault init failed — passwords will not persist.\n");
}
// 4a. History engine (SQLite DB for visits + bookmarks)
char historyPath[MAX_PATH];
_snprintf_s(historyPath, sizeof(historyPath), _TRUNCATE, "%s\\history.db", vaultDir);
if (!HistoryEngine::Init(historyPath, /*incognito=*/false)) {
fprintf(stderr, "[Boot] WARNING: HistoryEngine init failed — history will not persist.\n");
} else {
fprintf(stdout, "[Boot] HistoryEngine initialized: %s\n", historyPath);
}
// 4b. Download manager
AeonSettings bootSettings = SettingsEngine::Load();
const char* downloadStartDir = (bootSettings.dl_path[0]) ? bootSettings.dl_path : nullptr;
if (!DownloadManager::Init(downloadStartDir)) {
fprintf(stderr, "[Boot] WARNING: DownloadManager init failed — downloads disabled.\n");
} else {
fprintf(stdout, "[Boot] DownloadManager initialized: %s\n",
DownloadManager::GetDownloadDir());
}
// 5. Load rendering engine DLL for this tier
AeonEngineVTable* engine = TierDispatcher_LoadEngine(&profile);
if (!engine) {
MessageBoxA(nullptr,
"Aeon could not load a rendering engine for your system.\n"
"Please visit browseaeon.com for troubleshooting.",
"Aeon Browser \u2014 Engine Error", MB_ICONERROR);
return 1;
}
g_Engine = engine;
// Initialize the engine (creates COM apartment, WebView2 env, etc.)
if (!engine->Init(&profile, hInstance)) {
MessageBoxA(nullptr,
"Aeon rendering engine failed to initialize.\n"
"Ensure Microsoft Edge WebView2 Runtime is installed.",
"Aeon Browser \u2014 Engine Error", MB_ICONERROR);
return 1;
}
// Wire engine event callbacks — CRITICAL: without this, the engine
// silently discards all navigation events and BrowserChrome never
// learns that pages loaded, titles changed, or URLs committed.
// NOTE: g_MainHwnd is set later (after CreateWindowExW), but these
// callbacks only fire asynchronously from the WebView2 message pump,
// so g_MainHwnd is guaranteed to be valid by invocation time.
{
static AeonEngineCallbacks cbs = {};
cbs.OnProgress = [](unsigned int tab_id, int pct) {
fprintf(stdout, "[Engine→Shell] Tab #%u progress: %d%%\n", tab_id, pct);
};
cbs.OnTitleChanged = [](unsigned int tab_id, const char* title) {
fprintf(stdout, "[Engine→Shell] Tab #%u title: \"%s\"\n",
tab_id, title ? title : "(null)");
if (g_MainHwnd)
BrowserChrome::UpdateTabTitle(g_MainHwnd, tab_id, title);
};
cbs.OnNavigated = [](unsigned int tab_id, const char* url) {
fprintf(stdout, "[Engine→Shell] Tab #%u navigated: %s\n",
tab_id, url ? url : "(null)");
if (g_MainHwnd)
BrowserChrome::UpdateTabUrl(g_MainHwnd, tab_id, url);
};
cbs.OnLoaded = [](unsigned int tab_id) {
fprintf(stdout, "[Engine→Shell] Tab #%u loaded\n", tab_id);
if (g_MainHwnd)
BrowserChrome::SetTabLoaded(g_MainHwnd, tab_id);
};
cbs.OnCrash = [](unsigned int tab_id, const char* reason) {
fprintf(stderr, "[Engine→Shell] CRASH: tab #%u — %s\n",
tab_id, reason ? reason : "unknown");
if (g_MainHwnd) {
// Navigate the crashed tab to the internal crash page
char crashUrl[512];
_snprintf_s(crashUrl, sizeof(crashUrl), _TRUNCATE,
"aeon://crash?tab=%u&reason=%s", tab_id,
reason ? reason : "unknown");
BrowserChrome::NavigateTab(g_MainHwnd, tab_id, crashUrl);
}
};
cbs.OnNewTab = [](unsigned int parent_id, const char* url) {
fprintf(stdout, "[Engine→Shell] NewTab: parent #%u → %s\n",
parent_id, url ? url : "(null)");
if (g_MainHwnd)
BrowserChrome::CreateTab(g_MainHwnd, url);
};
engine->SetCallbacks(&cbs);
fprintf(stdout, "[Boot] Engine callbacks wired (6 handlers).\n");
}
// 5. Tab Sleep Manager
TabSleepManager::Initialize((unsigned int)tier);
// 5b. AI — Tab Intelligence Engine
{
// Build resource budget from probe results
ResourceBudget aiBudget;
aiBudget.max_ram_bytes = (profile.ramBytes > (2ULL * 1024 * 1024 * 1024))
? 64 * 1024 * 1024 // 64 MB budget on 2GB+ systems
: 16 * 1024 * 1024; // 16 MB budget on low-RAM
aiBudget.cpu_class = (profile.cpu.hasAVX2) ? AEON_CPU_CLASS_AVX2 :
(profile.cpu.hasSSE4) ? AEON_CPU_CLASS_SSE4 :
AEON_CPU_CLASS_SSE2;
aiBudget.hive_offload_ok = false; // Hive mesh not yet active
aiBudget.target_latency_ms = 50; // 50ms target for tab classification
auto* tabAI = new AeonTabIntelligence();
if (tabAI->Initialize(aiBudget)) {
g_TabIntel = tabAI;
fprintf(stdout, "[Boot] AeonTabIntelligence initialized (tier=%s, RAM=%.0f MB, budget=%zu KB)\n",
AeonProbe::TierName(tier), (double)profile.ramBytes / (1024.0 * 1024.0),
aiBudget.max_ram_bytes / 1024);
} else {
fprintf(stderr, "[Boot] WARNING: AeonTabIntelligence init failed — AI tab grouping disabled.\n");
delete tabAI;
}
}
// 5c. AI — Journey Analytics Engine
{
ResourceBudget journeyBudget;
journeyBudget.max_ram_bytes = 32 * 1024 * 1024; // 32 MB for journey graphs
journeyBudget.cpu_class = (profile.cpu.hasAVX2) ? AEON_CPU_CLASS_AVX2 :
(profile.cpu.hasSSE4) ? AEON_CPU_CLASS_SSE4 :
AEON_CPU_CLASS_SSE2;
journeyBudget.hive_offload_ok = false;
journeyBudget.target_latency_ms = 100; // Journey detection is less latency-critical
auto* journeyAI = new AeonJourneyAnalytics();
if (journeyAI->Initialize(journeyBudget)) {
g_JourneyAI = journeyAI;
fprintf(stdout, "[Boot] AeonJourneyAnalytics initialized.\n");
} else {
fprintf(stderr, "[Boot] WARNING: AeonJourneyAnalytics init failed — journey tracking disabled.\n");
delete journeyAI;
}
}
// 6. Auto-updater (v2: staged install + background P2P poller)
AutoUpdater::CheckAndInstallStagedUpdate(); // Apply staged update BEFORE windows
if (settings.auto_update) {
AutoUpdater::Start({}); // Empty peer list — GCS-only until Hive is live
}
// 7. Create main window
WNDCLASSEXW wc = {};
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = AeonWndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIconA(hInstance, "IDI_AEON");
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = AEON_WINDOW_CLASS;
RegisterClassExW(&wc);
int W = GetSystemMetrics(SM_CXSCREEN) * 85 / 100;
int H = GetSystemMetrics(SM_CYSCREEN) * 85 / 100;
int X = (GetSystemMetrics(SM_CXSCREEN) - W) / 2;
int Y = (GetSystemMetrics(SM_CYSCREEN) - H) / 2;
// WS_EX_NOREDIRECTIONBITMAP: required for DWM Mica/Acrylic (Win11)
DWORD exStyle = (profile.osMajor >= 10 && profile.osBuild >= 22000)
? WS_EX_NOREDIRECTIONBITMAP : 0;
HWND hWnd = CreateWindowExW(
exStyle, AEON_WINDOW_CLASS, AEON_TITLE,
WS_OVERLAPPEDWINDOW, X, Y, W, H,
nullptr, nullptr, hInstance, nullptr);
if (!hWnd) return 1;
g_MainHwnd = hWnd; // Set before BrowserChrome::Create so callbacks are routed
// Enable DWM Mica on Windows 11
if (profile.osBuild >= 22000) {
MARGINS margins = { -1 };
DwmExtendFrameIntoClientArea(hWnd, &margins);
int backdropType = 2; // DWMSBT_MAINWINDOW (Mica)
DwmSetWindowAttribute(hWnd, 38 /*DWMWA_SYSTEMBACKDROP_TYPE*/,
&backdropType, sizeof(backdropType));
// Dark mode title bar (prevents white flash on any residual non-client area)
BOOL darkMode = TRUE;
DwmSetWindowAttribute(hWnd, 20 /*DWMWA_USE_IMMERSIVE_DARK_MODE*/,
&darkMode, sizeof(darkMode));
}
// NOTE: GWLP_USERDATA is reserved for BrowserChrome's ChromeState.
// Engine pointer is stored in g_Engine global instead.
// 8. AeonBridge — wire JS↔C++ for all internal aeon:// pages
AeonBridge::Init(hWnd, [](const char* url) {
char* urlCopy = _strdup(url);
if (urlCopy)
PostMessage(GetForegroundWindow(), WM_AEONBRIDGE,
BRIDGE_CMD_NAVIGATE, (LPARAM)urlCopy);
});
// 9. Browser chrome (tab strip, nav bar, WebView2 host)
BrowserChrome::Create(hWnd, &profile, engine);
// Captive portal — open in first tab if detected
const NetworkSentinel::SentinelState& sentState = NetworkSentinel::GetState();
if (sentState.need_captive_portal && sentState.captive_portal_url[0]) {
if (engine) engine->NewTab(hWnd, sentState.captive_portal_url);
fprintf(stdout, "[Boot] Captive portal tab: %s\n", sentState.captive_portal_url);
}
// 9b. Agent control pipe — Named Pipe IPC for shell control
AeonAgentPipe::Start(hWnd);
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
fprintf(stdout, "[Boot] Ready.\n\n");
// 10. Message loop
MSG msg = {};
while (GetMessageW(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
// 11. Cleanup
// AI engines — flush and free before tab/memory systems
if (g_JourneyAI) { g_JourneyAI->Shutdown(); delete g_JourneyAI; g_JourneyAI = nullptr; }
if (g_TabIntel) { g_TabIntel->Shutdown(); delete g_TabIntel; g_TabIntel = nullptr; }
AeonAgentPipe::Stop();
NetworkSentinel::StopMonitor();
TabSleepManager::Shutdown();
DownloadManager::Shutdown();
HistoryEngine::Shutdown();
PasswordVault::Lock();
if (engine && engine->Shutdown) engine->Shutdown();
fprintf(stdout, "[Boot] Aeon shutdown clean.\n");
return (int)msg.wParam;
}
// Window procedure
LRESULT CALLBACK AeonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
// ── Remove native title bar ──────────────────────────────────
case WM_NCCALCSIZE: {
if (wParam == TRUE) {
// Return 0 with TRUE wParam = client area fills entire window
// This eliminates the native title bar entirely.
// Preserve the auto-hide taskbar behavior by adjusting for it.
NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
HMONITOR hMon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(hMon, &mi);
if (IsZoomed(hWnd)) {
// When maximized, respect taskbar area
params->rgrc[0] = mi.rcWork;
}
return 0;
}
break;
}
// ── Hit-test for drag, resize, and caption buttons ───────────
case WM_NCHITTEST: {
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hWnd, &pt);
RECT rc;
GetClientRect(hWnd, &rc);
// Resize borders (6px) — always check first
const int BORDER = 6;
if (!IsZoomed(hWnd)) {
if (pt.y < BORDER) {
if (pt.x < BORDER) return HTTOPLEFT;
if (pt.x > rc.right - BORDER) return HTTOPRIGHT;
return HTTOP;
}
if (pt.y > rc.bottom - BORDER) {
if (pt.x < BORDER) return HTBOTTOMLEFT;
if (pt.x > rc.right - BORDER) return HTBOTTOMRIGHT;
return HTBOTTOM;
}
if (pt.x < BORDER) return HTLEFT;
if (pt.x > rc.right - BORDER) return HTRIGHT;
}
// Nav bar area (y < 40): check if over a button
if (pt.y < 40) {
int chromeHit = BrowserChrome::HitTest(hWnd, pt.x, pt.y);
if (chromeHit >= 0) {
// Over a clickable button → let WM_LBUTTONDOWN handle it
return HTCLIENT;
}
// Empty nav bar area → draggable caption
return HTCAPTION;
}
// Tab strip area (40-72): also check for tab clicks
if (pt.y < 72) {
int chromeHit = BrowserChrome::HitTest(hWnd, pt.x, pt.y);
if (chromeHit >= 0) return HTCLIENT;
return HTCAPTION; // Empty tab strip area = also draggable
}
return HTCLIENT;
}
case WM_PAINT: {
BrowserChrome::OnPaint(hWnd);
ValidateRect(hWnd, nullptr);
return 0;
}
case WM_SIZE:
BrowserChrome::OnSize(hWnd, LOWORD(lParam), HIWORD(lParam));
return 0;
case WM_ERASEBKGND:
return 1;
// ── Mouse events → BrowserChrome ─────────────────────────────
case WM_LBUTTONDOWN:
BrowserChrome::OnLButtonDown(hWnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_LBUTTONUP:
BrowserChrome::OnLButtonUp(hWnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_MOUSEMOVE:
BrowserChrome::OnMouseMove(hWnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_AEONBRIDGE: {
if ((int)wParam == BRIDGE_CMD_NAVIGATE) {
char* url = reinterpret_cast<char*>(lParam);
if (g_Engine && g_Engine->Navigate && url && url[0])
g_Engine->Navigate(0, url, nullptr);
free(url);
} else {
AeonBridge::HandleWmAeonBridge(wParam, lParam);
}
return 0;
}
// ── Keyboard shortcuts → BrowserChrome ───────────────────────
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (BrowserChrome::OnKeyDown(hWnd, wParam, lParam))
return 0;
break;
// ── Command from child controls (URL bar EDIT) ───────────────
case WM_COMMAND:
BrowserChrome::OnCommand(hWnd, LOWORD(wParam), HIWORD(wParam),
reinterpret_cast<HWND>(lParam));
return 0;
// ── Agent pipe command dispatch ─────────────────────────────────
case WM_AEON_AGENT:
AeonAgentPipe::HandleCommand(wParam, lParam);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hWnd, msg, wParam, lParam);
}