// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/mus/ws/server_window_drawn_tracker.h" #include "components/mus/ws/server_window.h" #include "components/mus/ws/server_window_drawn_tracker_observer.h" namespace mus { namespace ws { ServerWindowDrawnTracker::ServerWindowDrawnTracker( ServerWindow* window, ServerWindowDrawnTrackerObserver* observer) : window_(window), observer_(observer), drawn_(window->IsDrawn()) { AddObservers(); } ServerWindowDrawnTracker::~ServerWindowDrawnTracker() { RemoveObservers(); } void ServerWindowDrawnTracker::SetDrawn(ServerWindow* ancestor, bool drawn) { // If |windows_| is empty when this code runs, that means |window_| has been // destroyed. So set |window_| to nullptr, but make sure the right value is // sent to OnDrawnStateChanged(). ServerWindow* window = window_; if (windows_.empty()) window_ = nullptr; if (drawn == drawn_) return; drawn_ = drawn; observer_->OnDrawnStateChanged(ancestor, window, drawn); } void ServerWindowDrawnTracker::AddObservers() { if (!window_) return; for (ServerWindow* v = window_; v; v = v->parent()) { v->AddObserver(this); windows_.insert(v); } } void ServerWindowDrawnTracker::RemoveObservers() { for (ServerWindow* window : windows_) window->RemoveObserver(this); windows_.clear(); } void ServerWindowDrawnTracker::OnWindowDestroying(ServerWindow* window) { if (!drawn_) return; observer_->OnDrawnStateWillChange(window->parent(), window_, false); } void ServerWindowDrawnTracker::OnWindowDestroyed(ServerWindow* window) { // As windows are removed before being destroyed, resulting in // OnWindowHierarchyChanged() and us removing ourself as an observer, the only // window we should ever get notified of destruction on is |window_|. DCHECK_EQ(window, window_); RemoveObservers(); SetDrawn(nullptr, false); } void ServerWindowDrawnTracker::OnWillChangeWindowHierarchy( ServerWindow* window, ServerWindow* new_parent, ServerWindow* old_parent) { bool new_is_drawn = new_parent && new_parent->IsDrawn(); if (new_is_drawn) { for (ServerWindow* w = window_; new_is_drawn && w != old_parent; w = w->parent()) { new_is_drawn = w->visible(); } } if (drawn_ != new_is_drawn) { observer_->OnDrawnStateWillChange(new_is_drawn ? nullptr : old_parent, window_, new_is_drawn); } } void ServerWindowDrawnTracker::OnWindowHierarchyChanged( ServerWindow* window, ServerWindow* new_parent, ServerWindow* old_parent) { RemoveObservers(); AddObservers(); const bool is_drawn = window_->IsDrawn(); SetDrawn(is_drawn ? nullptr : old_parent, is_drawn); } void ServerWindowDrawnTracker::OnWillChangeWindowVisibility( ServerWindow* window) { bool will_change = false; if (drawn_) { // If |window_| is currently drawn, then any change of visibility of the // windows will toggle the drawn status. will_change = true; } else { // If |window| is currently visible, then it's becoming invisible, and so // |window_| will remain not drawn. if (window->visible()) { will_change = false; } else { bool is_drawn = (window->GetRoot() == window) || (window->parent() && window->parent()->IsDrawn()); if (is_drawn) { for (ServerWindow* w = window_; is_drawn && w != window; w = w->parent()) is_drawn = w->visible(); } will_change = drawn_ != is_drawn; } } if (will_change) { bool new_is_drawn = !drawn_; observer_->OnDrawnStateWillChange(new_is_drawn ? nullptr : window->parent(), window_, new_is_drawn); } } void ServerWindowDrawnTracker::OnWindowVisibilityChanged(ServerWindow* window) { const bool is_drawn = window_->IsDrawn(); SetDrawn(is_drawn ? nullptr : window->parent(), is_drawn); } } // namespace ws } // namespace mus