Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Unified Diff: chromecast/graphics/cast_window_manager_aura.cc

Issue 2636303002: [Chromecast] Add support for z-order and window focus. (Closed)
Patch Set: fix macro Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698