blob: 4ef7a757b4ffa00383528ded9e374e9a928d41fa [file] [log] [blame]
// Copyright 2018 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 "ui/aura/mus/embed_root.h"
#include "base/auto_reset.h"
#include "base/bind.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/mus/embed_root_delegate.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tracker.h"
namespace aura {
namespace {
// FocusClient implementation used for embedded windows. This has minimal
// checks as to what can get focus.
class EmbeddedFocusClient : public client::FocusClient, public WindowObserver {
public:
explicit EmbeddedFocusClient(Window* root) : root_(root) {
client::SetFocusClient(root, this);
}
~EmbeddedFocusClient() override {
client::SetFocusClient(root_, nullptr);
if (focused_window_)
focused_window_->RemoveObserver(this);
}
// client::FocusClient:
void AddObserver(client::FocusChangeObserver* observer) override {
observers_.AddObserver(observer);
}
void RemoveObserver(client::FocusChangeObserver* observer) override {
observers_.RemoveObserver(observer);
}
void FocusWindow(Window* window) override {
if (IsValidWindowForFocus(window) && window != GetFocusedWindow())
FocusWindowImpl(window);
}
void ResetFocusWithinActiveWindow(Window* window) override {
// This is never called in the embedding case.
NOTREACHED();
}
Window* GetFocusedWindow() override { return focused_window_; }
private:
bool IsValidWindowForFocus(Window* window) const {
return !window || (root_->Contains(window) && window->CanFocus());
}
void FocusWindowImpl(Window* window) {
Window* lost_focus = focused_window_;
if (lost_focus)
lost_focus->RemoveObserver(this);
focused_window_ = window;
if (focused_window_)
focused_window_->AddObserver(this);
WindowTracker window_tracker;
if (lost_focus)
window_tracker.Add(lost_focus);
for (auto& observer : observers_) {
observer.OnWindowFocused(
focused_window_,
window_tracker.Contains(lost_focus) ? lost_focus : nullptr);
}
if (window_tracker.Contains(lost_focus)) {
client::FocusChangeObserver* observer =
client::GetFocusChangeObserver(lost_focus);
if (observer)
observer->OnWindowFocused(focused_window_, lost_focus);
}
client::FocusChangeObserver* observer =
client::GetFocusChangeObserver(focused_window_);
if (observer) {
observer->OnWindowFocused(
focused_window_,
window_tracker.Contains(lost_focus) ? lost_focus : nullptr);
}
}
// WindowObserver:
void OnWindowDestroying(Window* window) override {
DCHECK_EQ(window, focused_window_);
}
// Root of the hierarchy this is the FocusClient for.
Window* const root_;
Window* focused_window_ = nullptr;
base::ObserverList<client::FocusChangeObserver>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedFocusClient);
};
} // namespace
EmbedRoot::~EmbedRoot() {
window_tree_client_->OnEmbedRootDestroyed(this);
// Makes use of window_tree_host_->window(), so needs to be destroyed before
// |window_tree_host_|.
focus_client_.reset();
}
Window* EmbedRoot::window() {
return window_tree_host_ ? window_tree_host_->window() : nullptr;
}
EmbedRoot::EmbedRoot(WindowTreeClient* window_tree_client,
EmbedRootDelegate* delegate,
ws::ClientSpecificId window_id)
: window_tree_client_(window_tree_client),
delegate_(delegate),
weak_factory_(this) {
window_tree_client_->tree_->ScheduleEmbedForExistingClient(
window_id, base::BindOnce(&EmbedRoot::OnScheduledEmbedForExistingClient,
weak_factory_.GetWeakPtr()));
}
void EmbedRoot::OnScheduledEmbedForExistingClient(
const base::UnguessableToken& token) {
token_ = token;
delegate_->OnEmbedTokenAvailable(token);
}
void EmbedRoot::OnEmbed(std::unique_ptr<WindowTreeHostMus> window_tree_host) {
focus_client_ =
std::make_unique<EmbeddedFocusClient>(window_tree_host->window());
window_tree_host_ = std::move(window_tree_host);
delegate_->OnEmbed(window());
}
void EmbedRoot::OnUnembed() {
delegate_->OnUnembed();
}
} // namespace aura