@@ -328,12 +328,44 @@ class Menu::Impl {
328328 }
329329 }
330330
331- // Handle window procedure delegate for menu commands
331+ // Handle window procedure delegate for menu commands and menu lifecycle events
332332 std::optional<LRESULT> HandleWindowProc (HWND hwnd,
333333 UINT message,
334334 WPARAM wparam,
335- LPARAM lparam) {
336- if (message == WM_COMMAND) {
335+ LPARAM lparam,
336+ Menu* menu) {
337+ // Handle menu lifecycle events
338+ if (message == WM_INITMENUPOPUP) {
339+ // wParam contains the HMENU handle of the popup menu being opened
340+ HMENU popup_menu = reinterpret_cast <HMENU>(wparam);
341+
342+ if (popup_menu == hmenu_) {
343+ // This is our menu being opened
344+ visible_ = true ;
345+
346+ // Emit menu opened event
347+ try {
348+ menu->Emit <MenuOpenedEvent>(id_);
349+ } catch (...) {
350+ // Protect against event emission exceptions
351+ }
352+ }
353+ } else if (message == WM_UNINITMENUPOPUP) {
354+ // wParam contains the HMENU handle of the popup menu being closed
355+ HMENU popup_menu = reinterpret_cast <HMENU>(wparam);
356+
357+ if (popup_menu == hmenu_) {
358+ // This is our menu being closed
359+ visible_ = false ;
360+
361+ // Emit menu closed event
362+ try {
363+ menu->Emit <MenuClosedEvent>(id_);
364+ } catch (...) {
365+ // Protect against event emission exceptions
366+ }
367+ }
368+ } else if (message == WM_COMMAND) {
337369 // For WM_COMMAND from menus, wparam contains the menu item ID
338370 // When using popup menus (TrackPopupMenu), the full 32-bit ID is
339371 // preserved in wparam, unlike menu bars which only use 16-bit IDs
@@ -375,29 +407,29 @@ class Menu::Impl {
375407Menu::Menu (void * native_menu)
376408 : pimpl_(std::make_unique<Impl>(IdAllocator::Allocate<Menu>(),
377409 static_cast <HMENU>(native_menu))) {
378- // Register window procedure handler for menu commands
410+ // Register window procedure handler for menu commands and events
379411 HWND host_window = WindowMessageDispatcher::GetInstance ().GetHostWindow ();
380412 if (host_window) {
381413 pimpl_->window_proc_handle_id_ =
382414 WindowMessageDispatcher::GetInstance ().RegisterHandler (
383415 host_window,
384416 [this ](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
385- return pimpl_->HandleWindowProc (hwnd, message, wparam, lparam);
417+ return pimpl_->HandleWindowProc (hwnd, message, wparam, lparam, this );
386418 });
387419 }
388420}
389421
390422Menu::Menu ()
391423 : pimpl_(std::make_unique<Impl>(IdAllocator::Allocate<Menu>(),
392424 CreatePopupMenu ())) {
393- // Register window procedure handler for menu commands
425+ // Register window procedure handler for menu commands and events
394426 HWND host_window = WindowMessageDispatcher::GetInstance ().GetHostWindow ();
395427 if (host_window) {
396428 pimpl_->window_proc_handle_id_ =
397429 WindowMessageDispatcher::GetInstance ().RegisterHandler (
398430 host_window,
399431 [this ](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
400- return pimpl_->HandleWindowProc (hwnd, message, wparam, lparam);
432+ return pimpl_->HandleWindowProc (hwnd, message, wparam, lparam, this );
401433 });
402434 }
403435}
@@ -539,25 +571,24 @@ std::vector<std::shared_ptr<MenuItem>> Menu::GetAllItems() const {
539571}
540572
541573bool Menu::Open (double x, double y) {
542- pimpl_->visible_ = true ;
543-
544574 POINT pt = {static_cast <int >(x), static_cast <int >(y)};
545575
546576 // Get the host window for menus
547577 HWND host_window = WindowMessageDispatcher::GetInstance ().GetHostWindow ();
548578 if (!host_window) {
549- pimpl_->visible_ = false ;
550579 return false ;
551580 }
552581
553582 // Set the host window as foreground to ensure menu can be displayed
554583 SetForegroundWindow (host_window);
555584
556585 // Show the context menu using the host window
586+ // Note: TrackPopupMenu is a blocking call
587+ // - WM_INITMENUPOPUP is sent when the menu opens (triggers MenuOpenedEvent)
588+ // - WM_UNINITMENUPOPUP is sent when the menu closes (triggers MenuClosedEvent)
557589 TrackPopupMenu (pimpl_->hmenu_ , TPM_BOTTOMALIGN | TPM_LEFTALIGN, pt.x , pt.y , 0 ,
558590 host_window, nullptr );
559591
560- pimpl_->visible_ = false ;
561592 return true ;
562593}
563594
@@ -569,8 +600,12 @@ bool Menu::Open() {
569600
570601bool Menu::Close () {
571602 if (pimpl_->visible_ ) {
572- // Windows automatically closes popup menus when user clicks elsewhere
573- pimpl_->visible_ = false ;
603+ // Send WM_CANCELMODE to close any open menus
604+ HWND host_window = WindowMessageDispatcher::GetInstance ().GetHostWindow ();
605+ if (host_window) {
606+ // This will close the menu and trigger WM_UNINITMENUPOPUP
607+ SendMessage (host_window, WM_CANCELMODE, 0 , 0 );
608+ }
574609 return true ;
575610 }
576611 return false ;
0 commit comments