Index: content/browser/frame_host/popup_menu_helper_mac.mm |
diff --git a/content/browser/frame_host/popup_menu_helper_mac.mm b/content/browser/frame_host/popup_menu_helper_mac.mm |
index 5cef607e10edba1fffeecf1eb65dbd4e12c2e647..c33a667e552a49f8b719dc771e0e6a0f6e967e3b 100644 |
--- a/content/browser/frame_host/popup_menu_helper_mac.mm |
+++ b/content/browser/frame_host/popup_menu_helper_mac.mm |
@@ -2,11 +2,9 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#import <Carbon/Carbon.h> |
- |
#include "content/browser/frame_host/popup_menu_helper_mac.h" |
-#include "base/mac/scoped_nsobject.h" |
+#import "base/mac/scoped_nsobject.h" |
#import "base/mac/scoped_sending_event.h" |
#include "base/message_loop/message_loop.h" |
#include "content/browser/frame_host/frame_tree.h" |
@@ -28,10 +26,13 @@ bool g_allow_showing_popup_menus = true; |
} // namespace |
-PopupMenuHelper::PopupMenuHelper(RenderFrameHost* render_frame_host) |
- : render_frame_host_(static_cast<RenderFrameHostImpl*>(render_frame_host)), |
+PopupMenuHelper::PopupMenuHelper(Delegate* delegate, |
+ RenderFrameHost* render_frame_host) |
+ : delegate_(delegate), |
+ render_frame_host_(static_cast<RenderFrameHostImpl*>(render_frame_host)), |
menu_runner_(nil), |
- popup_was_hidden_(false) { |
+ popup_was_hidden_(false), |
+ weak_ptr_factory_(this) { |
notification_registrar_.Add( |
this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, |
Source<RenderWidgetHost>( |
@@ -42,6 +43,10 @@ PopupMenuHelper::PopupMenuHelper(RenderFrameHost* render_frame_host) |
render_frame_host->GetRenderViewHost()->GetWidget())); |
} |
+PopupMenuHelper::~PopupMenuHelper() { |
+ Hide(); |
+} |
+ |
void PopupMenuHelper::ShowPopupMenu( |
const gfx::Rect& bounds, |
int item_height, |
@@ -66,9 +71,15 @@ void PopupMenuHelper::ShowPopupMenu( |
[rwhvm->cocoa_view() retain]); |
// Display the menu. |
- menu_runner_ = [[WebMenuRunner alloc] initWithItems:items |
- fontSize:item_font_size |
- rightAligned:right_aligned]; |
+ base::scoped_nsobject<WebMenuRunner> runner([[WebMenuRunner alloc] |
+ initWithItems:items |
+ fontSize:item_font_size |
+ rightAligned:right_aligned]); |
+ |
+ // Take a weak reference so that Hide() can close the menu. |
+ menu_runner_ = runner; |
+ |
+ base::WeakPtr<PopupMenuHelper> weak_ptr(weak_ptr_factory_.GetWeakPtr()); |
{ |
// Make sure events can be pumped while the menu is up. |
@@ -82,30 +93,27 @@ void PopupMenuHelper::ShowPopupMenu( |
// be done manually. |
base::mac::ScopedSendingEvent sending_event_scoper; |
- // Now run a SYNCHRONOUS NESTED EVENT LOOP until the pop-up is finished. |
- [menu_runner_ runMenuInView:cocoa_view |
- withBounds:[cocoa_view flipRectToNSRect:bounds] |
- initialIndex:selected_item]; |
+ // Now run a NESTED EVENT LOOP until the pop-up is finished. |
+ [runner runMenuInView:cocoa_view |
+ withBounds:[cocoa_view flipRectToNSRect:bounds] |
+ initialIndex:selected_item]; |
} |
- if (!render_frame_host_) { |
- // Bad news, the RenderFrameHost got deleted while we were off running the |
- // menu. Nothing to do. |
- [menu_runner_ release]; |
- menu_runner_ = nil; |
- return; |
- } |
+ if (!weak_ptr) |
+ return; // Handle |this| being deleted. |
+ |
+ menu_runner_ = nil; |
- if (!popup_was_hidden_) { |
- if ([menu_runner_ menuItemWasChosen]) { |
- render_frame_host_->DidSelectPopupMenuItem( |
- [menu_runner_ indexOfSelectedItem]); |
- } else { |
+ // The RenderFrameHost may be deleted while running the menu, or it may have |
+ // requested the close. Don't notify in these cases. |
+ if (render_frame_host_ && !popup_was_hidden_) { |
+ if ([runner menuItemWasChosen]) |
+ render_frame_host_->DidSelectPopupMenuItem([runner indexOfSelectedItem]); |
+ else |
render_frame_host_->DidCancelPopupMenu(); |
- } |
} |
- [menu_runner_ release]; |
- menu_runner_ = nil; |
+ |
+ delegate_->OnMenuClosed(); // May delete |this|. |
} |
void PopupMenuHelper::Hide() { |