1 /** 2 * The master window procedure and the HWND → Widget registry. 3 * 4 * Every Deft window class is registered with the single `wndProc` below. It 5 * finds the `Widget` that owns the target `HWND` and forwards the message to 6 * `Widget.processMessage`, where per-widget handling lives. Lookup is by 7 * `GWLP_USERDATA` (set when the widget's handle is created), with the registry 8 * associative array as a fallback. 9 */ 10 module deft.platform.win32.wndproc; 11 12 version (Windows): 13 14 import core.sys.windows.windows; 15 16 import deft.widget : Widget; 17 18 /// HWND → Widget map. Accessed only from the single UI thread. 19 private __gshared Widget[HWND] g_widgets; 20 21 /// Register a widget under its HWND. 22 void registerWidget(HWND h, Widget w) 23 { 24 g_widgets[h] = w; 25 } 26 27 /// Remove a widget's HWND from the registry. 28 void unregisterWidget(HWND h) 29 { 30 g_widgets.remove(h); 31 } 32 33 /// Look up the widget that owns an HWND, or null. 34 Widget lookupWidget(HWND h) 35 { 36 if (auto p = h in g_widgets) 37 return *p; 38 return null; 39 } 40 41 /** 42 * The single window procedure shared by all Deft window classes. 43 * 44 * `extern(Windows)` callbacks must not let a D exception escape into the OS, so 45 * the dispatch is wrapped: any `Throwable` is swallowed and the message falls 46 * through to `DefWindowProcW`. 47 */ 48 extern (Windows) LRESULT wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) nothrow 49 { 50 try 51 { 52 Widget widget; 53 54 auto userData = GetWindowLongPtrW(hwnd, GWLP_USERDATA); 55 if (userData != 0) 56 widget = cast(Widget) cast(void*) userData; 57 else 58 widget = lookupWidget(hwnd); 59 60 if (widget !is null) 61 return widget.processMessage(msg, wParam, lParam); 62 } 63 catch (Throwable) 64 { 65 // Swallow: never propagate a D throwable through the Win32 dispatcher. 66 } 67 68 return DefWindowProcW(hwnd, msg, wParam, lParam); 69 }