fix: ensure menu-did-close is emitted for application menus (#49092)

fix: ensure menu-did-close is emitted for application menus

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
trop[bot]
2025-11-26 11:47:36 -06:00
committed by GitHub
parent 7eb6ff95e4
commit d2ae9ed69f
3 changed files with 22 additions and 14 deletions

View File

@@ -157,7 +157,8 @@ void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
if (rightmostMenuPoint > screenRight)
position.x = position.x - [menu size].width;
[popup_controllers_[window_id] setCloseCallback:std::move(close_callback)];
[popup_controllers_[window_id]
setPopupCloseCallback:std::move(close_callback)];
if (frame && frame->render_frame_host()) {
auto* rfh = frame->render_frame_host()->GetOutermostMainFrameOrEmbedder();

View File

@@ -28,7 +28,7 @@ class ElectronMenuModel;
NSMenu* __strong menu_;
BOOL isMenuOpen_;
BOOL useDefaultAccelerator_;
base::OnceClosure closeCallback;
base::OnceClosure popupCloseCallback;
}
// Builds a NSMenu from the pre-built model (must not be nil). Changes made
@@ -36,7 +36,7 @@ class ElectronMenuModel;
- (id)initWithModel:(electron::ElectronMenuModel*)model
useDefaultAccelerator:(BOOL)use;
- (void)setCloseCallback:(base::OnceClosure)callback;
- (void)setPopupCloseCallback:(base::OnceClosure)callback;
// Populate current NSMenu with |model|.
- (void)populateWithModel:(electron::ElectronMenuModel*)model;

View File

@@ -186,8 +186,8 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
model_ = nullptr;
}
- (void)setCloseCallback:(base::OnceClosure)callback {
closeCallback = std::move(callback);
- (void)setPopupCloseCallback:(base::OnceClosure)callback {
popupCloseCallback = std::move(callback);
}
- (void)populateWithModel:(electron::ElectronMenuModel*)model {
@@ -221,9 +221,9 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
isMenuOpen_ = NO;
if (model_)
model_->MenuWillClose();
if (!closeCallback.is_null()) {
content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
std::move(closeCallback));
if (!popupCloseCallback.is_null()) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, std::move(popupCloseCallback));
}
}
}
@@ -567,18 +567,25 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
if (!isMenuOpen_)
return;
// We should only respond to the top-level menu's close event.
if (menu != menu_)
return;
bool has_close_cb = !popupCloseCallback.is_null();
// There are two scenarios where we should emit menu-did-close:
// 1. It's a popup and the top level menu is closed.
// 2. It's an application menu, and the current menu's supermenu
// is the top-level menu.
if (menu != menu_) {
if (has_close_cb || menu.supermenu != menu_)
return;
}
isMenuOpen_ = NO;
if (model_)
model_->MenuWillClose();
// Post async task so that itemSelected runs before the close callback
// deletes the controller from the map which deallocates it
if (!closeCallback.is_null()) {
// deletes the controller from the map which deallocates it.
if (has_close_cb) {
content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
std::move(closeCallback));
std::move(popupCloseCallback));
}
}