Index: chromecast/graphics/cast_window_manager_aura.cc |
diff --git a/chromecast/graphics/cast_window_manager_aura.cc b/chromecast/graphics/cast_window_manager_aura.cc |
index b4d9dbcd0896f1180c237be5c1cfcbb851fe8dae..7260aa3c4ed260e58525218bf16a9468810d6731 100644 |
--- a/chromecast/graphics/cast_window_manager_aura.cc |
+++ b/chromecast/graphics/cast_window_manager_aura.cc |
@@ -6,6 +6,7 @@ |
#include "base/memory/ptr_util.h" |
#include "ui/aura/client/default_capture_client.h" |
+#include "ui/aura/client/focus_change_observer.h" |
#include "ui/aura/env.h" |
#include "ui/aura/layout_manager.h" |
#include "ui/aura/window.h" |
@@ -15,6 +16,15 @@ |
#include "ui/display/display.h" |
#include "ui/display/screen.h" |
+#define LOG_WINDOW_INFO(top_level, window) \ |
+ "top-level: " << (top_level)->id() << ": " << (top_level)->GetName() \ |
+ << ", window: " << (window)->id() << ": " \ |
+ << (window)->GetName() |
+ |
+namespace { |
+const bool kFocusFollowsVisibility = true; |
+} |
+ |
namespace chromecast { |
// An aura::WindowTreeHost that correctly converts input events. |
@@ -108,7 +118,7 @@ std::unique_ptr<CastWindowManager> CastWindowManager::Create( |
} |
CastWindowManagerAura::CastWindowManagerAura(bool enable_input) |
- : enable_input_(enable_input) {} |
+ : enable_input_(enable_input), focused_window_(nullptr) {} |
CastWindowManagerAura::~CastWindowManagerAura() { |
TearDown(); |
@@ -136,6 +146,7 @@ void CastWindowManagerAura::Setup() { |
window_tree_host_->compositor()->SetHostHasTransparentBackground(true); |
window_tree_host_->compositor()->SetBackgroundColor(SK_ColorTRANSPARENT); |
+ aura::client::SetFocusClient(window_tree_host_->window(), this); |
capture_client_.reset( |
new aura::client::DefaultCaptureClient(window_tree_host_->window())); |
@@ -150,8 +161,10 @@ void CastWindowManagerAura::TearDown() { |
if (!window_tree_host_) { |
return; |
} |
+ focused_window_ = nullptr; |
CastVSyncSettings::GetInstance()->RemoveObserver(this); |
capture_client_.reset(); |
+ aura::client::SetFocusClient(window_tree_host_->window(), nullptr); |
window_tree_host_.reset(); |
} |
@@ -165,7 +178,30 @@ void CastWindowManagerAura::AddWindow(gfx::NativeView child) { |
parent->AddChild(child); |
} |
- parent->StackChildAtTop(child); |
+ // Determine z-order relative to existing windows. |
halliwell
2017/01/19 20:49:17
This is ordering windows by ID? Is the assumption
Joshua LeVasseur
2017/01/23 23:38:32
Yes, we use this enum for setting window IDs. If
|
+ aura::Window::Windows windows = parent->children(); |
+ aura::Window* above = nullptr; |
+ aura::Window* below = nullptr; |
+ for (auto&& other : windows) { |
+ if (other == child) { |
+ continue; |
+ } |
+ if ((other->id() < child->id()) && (!below || other->id() > below->id())) { |
+ below = other; |
+ } else if ((other->id() > child->id()) && |
+ (!above || other->id() < above->id())) { |
+ above = other; |
+ } |
+ } |
+ |
+ // Adjust the z-order of the new child window. |
+ if (above) { |
+ parent->StackChildBelow(child, above); |
+ } else if (below) { |
+ parent->StackChildAbove(child, below); |
+ } else { |
+ parent->StackChildAtBottom(child); |
+ } |
child->SetBounds(window_tree_host_->window()->bounds()); |
} |
@@ -174,4 +210,177 @@ void CastWindowManagerAura::OnVSyncIntervalChanged(base::TimeDelta interval) { |
window_tree_host_->compositor()->SetAuthoritativeVSyncInterval(interval); |
} |
+void CastWindowManagerAura::OnWindowVisibilityChanged(aura::Window* window, |
+ bool visible) { |
+ if (!kFocusFollowsVisibility) { |
+ return; |
+ } |
+ if (!visible && (window == focused_window_)) { |
+ UpdateWindowFocus(focused_window_); |
+ } else if (visible) { |
+ UpdateWindowFocus(nullptr); |
+ } |
+} |
+ |
+void CastWindowManagerAura::OnWindowDestroying(aura::Window* window) { |
+ aura::Window* top_level = GetTopLevelWindow(window); |
+ DCHECK(top_level); |
+ LOG(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_) { |
+ UpdateWindowFocus(focused_window_); |
+ } |
+} |
+ |
+void CastWindowManagerAura::OnWindowHierarchyChanging( |
+ const HierarchyChangeParams& params) { |
+ if (params.new_parent && |
+ (aura::client::GetFocusClient(params.new_parent) == this)) { |
+ return; |
+ } |
+ |
+ 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 = GetTopLevelWindow(window); |
+ DCHECK(top_level); |
+ LOG(INFO) << "Dropping window, " << LOG_WINDOW_INFO(top_level, window); |
+ } else { |
+ ++iter; |
+ } |
+ } |
halliwell
2017/01/19 20:49:17
All of these focus change logic functions are kind
Joshua LeVasseur
2017/01/23 23:38:32
Done.
|
+ |
+ if (was_focused) { |
+ UpdateWindowFocus(focused_window_); |
+ } |
+} |
+ |
+void CastWindowManagerAura::AddObserver( |
+ aura::client::FocusChangeObserver* observer) { |
+ focus_observers_.AddObserver(observer); |
+} |
+ |
+void CastWindowManagerAura::RemoveObserver( |
+ aura::client::FocusChangeObserver* observer) { |
+ focus_observers_.RemoveObserver(observer); |
+} |
+ |
+void CastWindowManagerAura::FocusWindow(aura::Window* window) { |
+ if (window) { |
+ if (!window->CanFocus()) { |
+ return; |
+ } |
+ aura::Window* top_level = GetTopLevelWindow(window); |
+ DCHECK(top_level); |
+ LOG(INFO) << "Requesting focus for " << LOG_WINDOW_INFO(top_level, window); |
+ auto iter = |
+ std::find(focusable_windows_.begin(), focusable_windows_.end(), window); |
+ if (iter == focusable_windows_.end()) { |
+ window->AddObserver(this); |
+ focusable_windows_.push_back(window); |
+ } |
+ } |
+ |
+ UpdateWindowFocus(nullptr); |
+} |
+ |
+void CastWindowManagerAura::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); |
+ } |
+} |
+ |
+aura::Window* CastWindowManagerAura::GetFocusedWindow() { |
+ return focused_window_; |
+} |
+ |
+void CastWindowManagerAura::UpdateWindowFocus(aura::Window* skip) { |
+ aura::Window* window = GetWindowToFocus(skip); |
+ if (window == focused_window_) { |
+ return; |
+ } |
+ |
+ if (window) { |
+ aura::Window* top_level = GetTopLevelWindow(window); |
+ DCHECK(top_level); |
+ LOG(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; |
+ } |
+ } |
+ } |
+} |
+ |
+aura::Window* CastWindowManagerAura::GetWindowToFocus(aura::Window* skip) { |
+ aura::Window* next = nullptr; |
+ aura::Window* next_top_level = nullptr; |
+ for (auto iter = focusable_windows_.begin(); iter != focusable_windows_.end(); |
+ ++iter) { |
+ aura::Window* window = *iter; |
+ if (window == skip || !window->CanFocus() || |
+ (kFocusFollowsVisibility && !window->IsVisible())) { |
+ continue; |
+ } |
+ |
+ aura::Window* top_level = GetTopLevelWindow(window); |
+ DCHECK(window_tree_host_->window()->Contains(top_level)); |
+ if (top_level && (!next || top_level->id() >= next_top_level->id())) { |
+ next = window; |
+ next_top_level = top_level; |
+ } |
+ } |
+ return next; |
+} |
+ |
+aura::Window* CastWindowManagerAura::GetTopLevelWindow(aura::Window* window) { |
+ while (window->parent() && window->parent() != window_tree_host_->window()) { |
+ window = window->parent(); |
+ } |
+ return window; |
+} |
+ |
} // namespace chromecast |