Index: chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm |
diff --git a/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm b/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm |
index dc0c944553aff9f5ae512a7637e3928446d123d0..edc64d7dc26c0aea88e60ae322990e953624328c 100644 |
--- a/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm |
+++ b/chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm |
@@ -6,6 +6,8 @@ |
#import <Cocoa/Cocoa.h> |
+#include "base/bind.h" |
+#include "base/message_loop.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/ui/browser.h" |
#include "chrome/browser/ui/browser_window.h" |
@@ -52,7 +54,8 @@ WebIntentPickerCocoa::WebIntentPickerCocoa() |
: delegate_(NULL), |
model_(NULL), |
browser_(NULL), |
- controller_(NULL) { |
+ controller_(nil), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
Nico
2012/02/03 23:27:07
this macro is only needed for msvc i think
groby-ooo-7-16
2012/02/06 22:30:19
Done.
|
} |
@@ -63,7 +66,8 @@ WebIntentPickerCocoa::WebIntentPickerCocoa(Browser* browser, |
: delegate_(delegate), |
model_(model), |
browser_(browser), |
- controller_(NULL) { |
+ controller_(nil), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
model_->set_observer(this); |
DCHECK(browser); |
@@ -91,28 +95,43 @@ WebIntentPickerCocoa::~WebIntentPickerCocoa() { |
void WebIntentPickerCocoa::Close() { |
} |
-void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) { |
- DCHECK(controller_); |
- scoped_nsobject<NSMutableArray> urlArray( |
- [[NSMutableArray alloc] initWithCapacity:model->GetItemCount()]); |
- |
- for (size_t i = 0; i < model->GetItemCount(); ++i) { |
- const WebIntentPickerModel::Item& item = model->GetItemAt(i); |
+void WebIntentPickerCocoa::PerformDelayedLayout() { |
+ // Check to see if a layout has already been scheduled. |
Nico
2012/02/03 23:27:07
indent only 2
groby-ooo-7-16
2012/02/06 22:30:19
Done.
|
+ if (weak_ptr_factory_.HasWeakPtrs()) |
+ return; |
+ |
+ // Delay performing layout by a second so that all the animations from |
+ // InfoBubbleWindow and origin updates from BaseBubbleController finish, so |
+ // that we don't all race trying to change the frame's origin. |
+ // |
+ // Using MessageLoop is superior here to |-performSelector:| because it will |
+ // not retain its target; if the child outlives its parent, zombies get left |
+ // behind (http://crbug.com/59619). This will cancel the scheduled task if |
+ // the controller get destroyed before the message |
+ // can be delivered. |
Nico
2012/02/03 23:27:07
This looks familiar. Can this code be factored out
groby-ooo-7-16
2012/02/06 22:30:19
It _is_ familiar. The PageInfoBubble does _almost_
Nico
2012/02/06 22:39:38
:-/
|
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, |
+ base::Bind(&WebIntentPickerCocoa::PerformLayout, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ 100 /* milliseconds */); |
+} |
- [urlArray addObject: |
- [NSString stringWithUTF8String:item.url.spec().c_str()]]; |
- [controller_ replaceImageAtIndex:i withImage:item.favicon.ToNSImage()]; |
- } |
+void WebIntentPickerCocoa::PerformLayout() { |
+ DCHECK(controller_); |
+ // If the window is animating closed when this is called, the |
+ // animation could be holding the last reference to |controller_| |
+ // (and thus |this|). Pin it until the task is completed. |
+ scoped_nsobject<WebIntentBubbleController> keep_alive([controller_ retain]); |
+ [controller_ performLayoutWithModel:model_]; |
+} |
- [controller_ setServiceURLs:urlArray]; |
+void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) { |
+ PerformDelayedLayout(); |
} |
void WebIntentPickerCocoa::OnFaviconChanged(WebIntentPickerModel* model, |
size_t index) { |
- DCHECK(controller_); |
- |
- const WebIntentPickerModel::Item& item = model->GetItemAt(index); |
- [controller_ replaceImageAtIndex:index withImage:item.favicon.ToNSImage()]; |
+ // We don't handle individual icon changes - just redo the whole model. |
+ PerformDelayedLayout(); |
} |
void WebIntentPickerCocoa::OnInlineDisposition(WebIntentPickerModel* model) { |
@@ -133,6 +152,7 @@ void WebIntentPickerCocoa::OnInlineDisposition(WebIntentPickerModel* model) { |
[controller_ setInlineDispositionTabContents: |
inline_disposition_tab_contents_.get()]; |
+ PerformDelayedLayout(); |
delegate_->OnInlineDispositionWebContentsCreated(web_contents); |
} |