Repository: godotengine/godot (language: cpp)

Issue:
PopupMenu with prefer_native_menu=true does not emit popup_hide signal on Windows
### Tested versions

v4.3.stable.mono.official [77dcf97d8]

### System information

Godot v4.3.stable.mono - Windows 10.0.26100 - Vulkan (Forward+) - dedicated AMD Radeon RX 6800M (Advanced Micro Devices, Inc.; 32.0.12033.1030) - AMD Ryzen 9 5980HX with Radeon Graphics (16 Threads)

### Issue description

- When using PopUpMenu to create a right click context menu with prefer_native_menu set to true the popup_hide signal is not emitted. 
- On MacOS with prefer_native_menu set to true the popup_hide signal is emitted as expected. 
- Also when prefer_native_menu is set to false the popup_hide signal is emitted as expected.

### Steps to reproduce

- Create empty project
- Add some Buttons
- Add a PopUpMenu with prefer_native_menu=true
- Add a script that when right click on button calls the PopUpMenu popup() mthod
- In the same script connect the popup_hide signal to a function
- Dismiss the PopUpMenu by clicking somewhere else
- Signal should be emitted

### Minimal reproduction project (MRP)

[bug-popup-menu.zip](https://github.com/user-attachments/files/18282528/bug-popup-menu.zip)

I also recorded a video to better explain the issue.
https://github.com/user-attachments/assets/db3bec37-dbdf-4edb-ba74-f96efda158bb


Discussion / hints:
Searched around the source code and this maybe isn't a bug, but a missing feature, the set_popup_close_callback method that is used to emit the popup_hide signal is marked as not supported in the windows specific implementation. 

https://github.com/godotengine/godot/blob/2582793d408ade0b6ed42f913ae33e7da5fb9184/platform/windows/native_menu_windows.cpp#L202-L204

Fix patch:
diff --git a/doc/classes/NativeMenu.xml b/doc/classes/NativeMenu.xml
index 2b9e41410688..6081d7afc51e 100644
--- a/doc/classes/NativeMenu.xml
+++ b/doc/classes/NativeMenu.xml
@@ -366,7 +366,7 @@
 			<param index="0" name="rid" type="RID" />
 			<description>
 				Returns global menu close callback.
-				b]Note:[/b] This method is implemented only on macOS.
+				[b]Note:[/b] This method is implemented on macOS and Windows.
 			</description>
 		</method>
 		<method name="get_popup_open_callback" qualifiers="const">
@@ -708,7 +708,7 @@
 			<description>
 				Registers callable to emit when the menu is about to show.
 				[b]Note:[/b] The OS can simulate menu opening to track menu item changes and global shortcuts, in which case the corresponding close callback is not triggered. Use [method is_opened] to check if the menu is currently opened.
-				[b]Note:[/b] This method is implemented only on macOS.
+				[b]Note:[/b] This method is implemented on macOS and Windows.
 			</description>
 		</method>
 		<method name="set_popup_open_callback">
diff --git a/platform/windows/native_menu_windows.cpp b/platform/windows/native_menu_windows.cpp
index 9fa2849e7b96..84d9302403e4 100644
--- a/platform/windows/native_menu_windows.cpp
+++ b/platform/windows/native_menu_windows.cpp
@@ -177,6 +177,16 @@ void NativeMenuWindows::popup(const RID &p_rid, const Vector2i &p_position) {
 	}
 	SetForegroundWindow(hwnd);
 	TrackPopupMenuEx(md->menu, flags, p_position.x, p_position.y, hwnd, nullptr);
+
+	if (md->close_cb.is_valid()) {
+		Variant ret;
+		Callable::CallError ce;
+		md->close_cb.callp(nullptr, 0, ret, ce);
+		if (ce.error != Callable::CallError::CALL_OK) {
+			ERR_PRINT(vformat("Failed to execute popup close callback: %s.", Variant::get_callable_error_text(md->close_cb, nullptr, 0, ce)));
+		}
+	}
+
 	PostMessage(hwnd, WM_NULL, 0, 0);
 }
 
@@ -200,12 +210,17 @@ Callable NativeMenuWindows::get_popup_open_callback(const RID &p_rid) const {
 }
 
 void NativeMenuWindows::set_popup_close_callback(const RID &p_rid, const Callable &p_callback) {
-	// Not supported.
+	MenuData *md = menus.get_or_null(p_rid);
+	ERR_FAIL_NULL(md);
+
+	md->close_cb = p_callback;
 }
 
 Callable NativeMenuWindows::get_popup_close_callback(const RID &p_rid) const {
-	// Not supported.
-	return Callable();
+	const MenuData *md = menus.get_or_null(p_rid);
+	ERR_FAIL_NULL_V(md, Callable());
+
+	return md->close_cb;
 }
 
 void NativeMenuWindows::set_minimum_width(const RID &p_rid, float p_width) {
diff --git a/platform/windows/native_menu_windows.h b/platform/windows/native_menu_windows.h
index 09e4640b4003..c23ac61fa258 100644
--- a/platform/windows/native_menu_windows.h
+++ b/platform/windows/native_menu_windows.h
@@ -61,6 +61,8 @@ class NativeMenuWindows : public NativeMenu {
 
 	struct MenuData {
 		HMENU menu = 0;
+
+		Callable close_cb;
 		bool is_rtl = false;
 	};
 


Test patch: