123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- // Copyright 2017 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 "chromecast/graphics/cast_focus_client_aura.h"
- #include "base/containers/contains.h"
- #include "base/logging.h"
- #include "ui/aura/window.h"
- #define LOG_WINDOW_INFO(top_level, window) \
- "top-level: " << (top_level)->GetId() << ": '" << (top_level)->GetName() \
- << "', window: " << (window)->GetId() << ": '" \
- << (window)->GetName() << "'"
- namespace chromecast {
- CastFocusClientAura::CastFocusClientAura() : focused_window_(nullptr) {}
- CastFocusClientAura::~CastFocusClientAura() {
- focused_window_ = nullptr;
- for (aura::Window* window : focusable_windows_) {
- window->RemoveObserver(this);
- }
- focusable_windows_.clear();
- }
- aura::Window* CastFocusClientAura::GetFocusedWindow() {
- return focused_window_;
- }
- void CastFocusClientAura::AddObserver(
- aura::client::FocusChangeObserver* observer) {
- focus_observers_.AddObserver(observer);
- }
- void CastFocusClientAura::RemoveObserver(
- aura::client::FocusChangeObserver* observer) {
- focus_observers_.RemoveObserver(observer);
- }
- void CastFocusClientAura::OnWindowVisibilityChanged(aura::Window* window,
- bool visible) {
- if (!visible && (window == focused_window_)) {
- // The focused window just lost visibility, so de-focus it.
- UpdateWindowFocus();
- } else if (visible) {
- // The window that just became visible might be the most appropriate window
- // to have focus.
- UpdateWindowFocus();
- }
- }
- // One of our observed windows is being destroyed.
- // We observe each window that has the potential for being focused,
- // so this window needs to be removed from the list of focusable windows.
- void CastFocusClientAura::OnWindowDestroying(aura::Window* window) {
- aura::Window* top_level = GetZOrderWindow(window);
- DCHECK(top_level);
- DLOG(INFO) << "Removing window, " << LOG_WINDOW_INFO(top_level, window);
- auto iter =
- std::find(focusable_windows_.begin(), focusable_windows_.end(), window);
- if (iter != focusable_windows_.end()) {
- focusable_windows_.erase(iter);
- window->RemoveObserver(this);
- }
- if (window == focused_window_) {
- // De-focus the window that is being destroyed.
- UpdateWindowFocus();
- }
- }
- // Update focus if a window is entering or leaving our hierarchy.
- void CastFocusClientAura::OnWindowHierarchyChanging(
- const HierarchyChangeParams& params) {
- if (params.new_parent &&
- (aura::client::GetFocusClient(params.new_parent) == this)) {
- if (params.old_parent == params.new_parent) {
- // A window is moving within our hierarchy.
- return;
- } else {
- // A window is entering our hierarchy, so we need to consider
- // focusing it.
- FocusWindow(params.target);
- return;
- }
- }
- // The window is leaving our hierarchy, so stop tracking it.
- // It could contain multiple windows that were focused, so lets stop tracking
- // them all.
- auto iter = focusable_windows_.begin();
- bool was_focused = false;
- while (iter != focusable_windows_.end()) {
- aura::Window* window = *iter;
- if (params.target == window || params.target->Contains(window)) {
- window->RemoveObserver(this);
- was_focused |= window == focused_window_;
- iter = focusable_windows_.erase(iter);
- aura::Window* top_level = GetZOrderWindow(window);
- DCHECK(top_level);
- DLOG(INFO) << "Dropping window, " << LOG_WINDOW_INFO(top_level, window);
- } else {
- ++iter;
- }
- }
- if (was_focused) {
- // The window that was removed from our hierarchy was the focused window, so
- // de-focus it.
- UpdateWindowFocus();
- }
- }
- // An explicit request to focus a window.
- // We lock focus to the top-most high-level window, and so will ignore this
- // focus request if it isn't for the topmost window. If it is for a lower
- // window, then we'll track it to focus it later when it rises to the top.
- void CastFocusClientAura::FocusWindow(aura::Window* window) {
- if (window) {
- if (!window->CanFocus()) {
- return;
- }
- aura::Window* top_level = GetZOrderWindow(window);
- DCHECK(top_level);
- DLOG(INFO) << "Requesting focus for " << LOG_WINDOW_INFO(top_level, window);
- if (!base::Contains(focusable_windows_, window)) {
- // We're not yet tracking this focusable window, so start tracking it as a
- // potential focus target.
- window->AddObserver(this);
- focusable_windows_.push_back(window);
- }
- }
- // Check whether this new window is the most appropriate to focus.
- UpdateWindowFocus();
- }
- // Finds the top-most window, and if it doesn't have focus, then gives it focus.
- void CastFocusClientAura::UpdateWindowFocus() {
- aura::Window* window = GetWindowToFocus();
- if (window == focused_window_) {
- return;
- }
- if (window) {
- aura::Window* top_level = GetZOrderWindow(window);
- DCHECK(top_level);
- DLOG(INFO) << "Switching focus to " << LOG_WINDOW_INFO(top_level, window);
- }
- aura::Window* unfocus_window = focused_window_;
- focused_window_ = window;
- for (aura::client::FocusChangeObserver& observer : focus_observers_) {
- observer.OnWindowFocused(focused_window_, unfocus_window);
- if (focused_window_ != window) {
- // The observer changed focused_window_.
- return;
- }
- }
- if (unfocus_window) {
- aura::client::FocusChangeObserver* focus_observer =
- aura::client::GetFocusChangeObserver(unfocus_window);
- if (focus_observer) {
- focus_observer->OnWindowFocused(focused_window_, unfocus_window);
- if (focused_window_ != window) {
- // The observer changed focused_window_.
- return;
- }
- }
- }
- if (focused_window_) {
- aura::client::FocusChangeObserver* focus_observer =
- aura::client::GetFocusChangeObserver(focused_window_);
- if (focus_observer) {
- focus_observer->OnWindowFocused(focused_window_, unfocus_window);
- if (focused_window_ != window) {
- // The observer changed focused_window_.
- return;
- }
- }
- }
- }
- // Returns the most appropriate window to have focus.
- // A focusable window could be anywhere within its window hierarchy, and we
- // choose based on the z-order of the top-level window in its hierarchy.
- aura::Window* CastFocusClientAura::GetWindowToFocus() {
- aura::Window* next = nullptr;
- aura::Window* next_top_level = nullptr;
- for (aura::Window* window : focusable_windows_) {
- if (!window->CanFocus() || !window->IsVisible()) {
- continue;
- }
- // Compare z-order of top-level windows using the window IDs.
- aura::Window* top_level = GetZOrderWindow(window);
- DCHECK(top_level);
- if (!next || top_level->GetId() >= next_top_level->GetId()) {
- next = window;
- next_top_level = top_level;
- }
- }
- return next;
- }
- const aura::Window* CastFocusClientAura::GetZOrderWindow(
- const aura::Window* window) const {
- while (window->parent() && !window->parent()->IsRootWindow()) {
- window = window->parent();
- }
- return window;
- }
- void CastFocusClientAura::ResetFocusWithinActiveWindow(aura::Window* window) {
- // Sets focus to |window| if it's within the active window (a child of the
- // focused window).
- if (focused_window_ && focused_window_->Contains(window)) {
- FocusWindow(window);
- }
- }
- void CastFocusClientAura::AddObserver(wm::ActivationChangeObserver* observer) {}
- void CastFocusClientAura::RemoveObserver(
- wm::ActivationChangeObserver* observer) {}
- void CastFocusClientAura::ActivateWindow(aura::Window* window) {}
- void CastFocusClientAura::DeactivateWindow(aura::Window* window) {}
- const aura::Window* CastFocusClientAura::GetActiveWindow() const {
- return nullptr;
- }
- aura::Window* CastFocusClientAura::GetActivatableWindow(
- aura::Window* window) const {
- return window;
- }
- const aura::Window* CastFocusClientAura::GetToplevelWindow(
- const aura::Window* window) const {
- return GetZOrderWindow(window);
- }
- bool CastFocusClientAura::CanActivateWindow(const aura::Window* window) const {
- return true;
- }
- } // namespace chromecast
|