| Index: mojo/services/public/cpp/view_manager/lib/view.cc
|
| diff --git a/mojo/services/public/cpp/view_manager/lib/view.cc b/mojo/services/public/cpp/view_manager/lib/view.cc
|
| index 1ed7a62b638711fde4fdf8ea60ecc4a02b16ac94..0880958b0d7ca4c06e49e57cc67ec9395b94b7ca 100644
|
| --- a/mojo/services/public/cpp/view_manager/lib/view.cc
|
| +++ b/mojo/services/public/cpp/view_manager/lib/view.cc
|
| @@ -4,10 +4,13 @@
|
|
|
| #include "mojo/services/public/cpp/view_manager/view.h"
|
|
|
| +#include <set>
|
| +
|
| #include "mojo/public/cpp/application/service_provider_impl.h"
|
| #include "mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h"
|
| #include "mojo/services/public/cpp/view_manager/lib/view_private.h"
|
| #include "mojo/services/public/cpp/view_manager/view_observer.h"
|
| +#include "mojo/services/public/cpp/view_manager/view_tracker.h"
|
|
|
| namespace mojo {
|
|
|
| @@ -225,7 +228,7 @@ void View::SetVisible(bool value) {
|
| static_cast<ViewManagerClientImpl*>(manager_)->SetVisible(id_, value);
|
| FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanging(this));
|
| visible_ = value;
|
| - FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanged(this));
|
| + NotifyViewVisibilityChanged(this);
|
| }
|
|
|
| void View::SetSharedProperty(const std::string& name,
|
| @@ -503,4 +506,52 @@ void View::LocalSetDrawn(bool value) {
|
| FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDrawnChanged(this));
|
| }
|
|
|
| +void View::NotifyViewVisibilityChanged(View* target) {
|
| + if (!NotifyViewVisibilityChangedDown(target)) {
|
| + return; // |this| has been deleted.
|
| + }
|
| + NotifyViewVisibilityChangedUp(target);
|
| +}
|
| +
|
| +bool View::NotifyViewVisibilityChangedAtReceiver(View* target) {
|
| + // |this| may be deleted during a call to OnViewVisibilityChanged() on one
|
| + // of the observers. We create an local observer for that. In that case we
|
| + // exit without further access to any members.
|
| + ViewTracker tracker;
|
| + tracker.Add(this);
|
| + FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanged(target));
|
| + return tracker.Contains(this);
|
| +}
|
| +
|
| +bool View::NotifyViewVisibilityChangedDown(View* target) {
|
| + if (!NotifyViewVisibilityChangedAtReceiver(target))
|
| + return false; // |this| was deleted.
|
| + std::set<const View*> child_already_processed;
|
| + bool child_destroyed = false;
|
| + do {
|
| + child_destroyed = false;
|
| + for (View::Children::const_iterator it = children_.begin();
|
| + it != children_.end(); ++it) {
|
| + if (!child_already_processed.insert(*it).second)
|
| + continue;
|
| + if (!(*it)->NotifyViewVisibilityChangedDown(target)) {
|
| + // |*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 View::NotifyViewVisibilityChangedUp(View* target) {
|
| + // Start with the parent as we already notified |this|
|
| + // in NotifyViewVisibilityChangedDown.
|
| + for (View* view = parent(); view; view = view->parent()) {
|
| + bool ret = view->NotifyViewVisibilityChangedAtReceiver(target);
|
| + DCHECK(ret);
|
| + }
|
| +}
|
| +
|
| } // namespace mojo
|
|
|