Index: ui/aura/window.cc |
diff --git a/ui/aura/window.cc b/ui/aura/window.cc |
index eef013cf7d26c88f20afbce674ebcb3d8954123e..e8d2891b15ca59ede83bb28fc5808a1065d5fa43 100644 |
--- a/ui/aura/window.cc |
+++ b/ui/aura/window.cc |
@@ -23,6 +23,7 @@ |
#include "ui/aura/layout_manager.h" |
#include "ui/aura/root_window.h" |
#include "ui/aura/window_delegate.h" |
+#include "ui/aura/window_destruction_observer.h" |
#include "ui/aura/window_observer.h" |
#include "ui/base/animation/multi_animation.h" |
#include "ui/compositor/compositor.h" |
@@ -982,29 +983,56 @@ void Window::NotifyWindowHierarchyChangeAtReceiver( |
void Window::NotifyWindowVisibilityChanged(aura::Window* target, |
bool visible) { |
- NotifyWindowVisibilityChangedDown(target, visible); |
+ if (!NotifyWindowVisibilityChangedDown(target, visible)) { |
+ return; // |this| has been deleted. |
+ } |
NotifyWindowVisibilityChangedUp(target, visible); |
} |
-void Window::NotifyWindowVisibilityChangedAtReceiver(aura::Window* target, |
+bool Window::NotifyWindowVisibilityChangedAtReceiver(aura::Window* target, |
bool visible) { |
+ // |this| may be deleted during a call to OnWindowVisibilityChanged |
+ // on one of the observers. We create an local observer for that. In |
+ // that case we exit without further access to any members. |
+ WindowDestructionObserver destruction_observer(this); |
+ AddObserver(&destruction_observer); |
Ben Goodger (Google)
2013/03/19 21:21:41
WDO's ctor should just add the observer. Likewise
sschmitz
2013/03/19 22:12:13
Done.
|
FOR_EACH_OBSERVER(WindowObserver, observers_, |
OnWindowVisibilityChanged(target, visible)); |
+ if (destruction_observer.destroyed()) |
Ben Goodger (Google)
2013/03/19 21:21:41
... then the rest of this function is simply
retu
sschmitz
2013/03/19 22:12:13
Done.
|
+ return false; // |this| has been deleted. |
+ RemoveObserver(&destruction_observer); |
+ return true; |
} |
-void Window::NotifyWindowVisibilityChangedDown(aura::Window* target, |
+bool Window::NotifyWindowVisibilityChangedDown(aura::Window* target, |
bool visible) { |
- NotifyWindowVisibilityChangedAtReceiver(target, visible); |
- for (Window::Windows::const_iterator it = children_.begin(); |
- it != children_.end(); ++it) { |
- (*it)->NotifyWindowVisibilityChangedDown(target, visible); |
- } |
+ if (!NotifyWindowVisibilityChangedAtReceiver(target, visible)) |
+ return false; // |this| was deleted. |
+ std::set<const Window*> child_already_processed; |
+ bool child_destroyed = false; |
+ do { |
+ child_destroyed = false; |
+ for (Window::Windows::const_iterator it = children_.begin(); |
+ it != children_.end(); ++it) { |
+ if (!child_already_processed.insert(*it).second) |
+ continue; |
+ if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) { |
+ // |*it| was deleted, |it| is invalid and |children_| has changed. |
+ // We exit the current for-loop and enter a new one. |
+ child_destroyed = true; |
+ break; |
+ } |
+ } |
+ } while (child_destroyed); |
+ return true; |
} |
void Window::NotifyWindowVisibilityChangedUp(aura::Window* target, |
bool visible) { |
- for (Window* window = this; window; window = window->parent()) |
- window->NotifyWindowVisibilityChangedAtReceiver(target, visible); |
+ for (Window* window = this; window; window = window->parent()) { |
+ bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target, visible); |
+ DCHECK(ret); |
+ } |
} |
void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds, |