Commit f99b42d4 authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

aura: make the EmbedRoot's window have a FocusClient

This is needed to handle focus changes correctly. The focus client in
this case is extremely minimal.

BUG=821602
TEST=covered by test

Change-Id: I6e1cbd686edf8e0080b8a21a28c3ddeae4e640a4
Reviewed-on: https://chromium-review.googlesource.com/965445
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543728}
parent c80fc114
...@@ -6,17 +6,99 @@ ...@@ -6,17 +6,99 @@
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "base/bind.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/embed_root_delegate.h"
#include "ui/aura/mus/window_tree_client.h" #include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tracker.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
namespace aura { 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* previously_focused_window = focused_window_;
if (previously_focused_window)
previously_focused_window->RemoveObserver(this);
focused_window_ = window;
if (focused_window_)
focused_window_->AddObserver(this);
WindowTracker window_tracker;
if (previously_focused_window)
window_tracker.Add(previously_focused_window);
for (auto& observer : observers_) {
observer.OnWindowFocused(
focused_window_, window_tracker.Contains(previously_focused_window)
? previously_focused_window
: 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> observers_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedFocusClient);
};
} // namespace
EmbedRoot::~EmbedRoot() { EmbedRoot::~EmbedRoot() {
window_tree_client_->OnEmbedRootDestroyed(this); window_tree_client_->OnEmbedRootDestroyed(this);
// Makes use of window_tree_host_->window(), so needs to be destroyed before
// |window_tree_host_|.
focus_client_.reset();
} }
aura::Window* EmbedRoot::window() { Window* EmbedRoot::window() {
return window_tree_host_ ? window_tree_host_->window() : nullptr; return window_tree_host_ ? window_tree_host_->window() : nullptr;
} }
...@@ -38,6 +120,8 @@ void EmbedRoot::OnScheduledEmbedForExistingClient( ...@@ -38,6 +120,8 @@ void EmbedRoot::OnScheduledEmbedForExistingClient(
} }
void EmbedRoot::OnEmbed(std::unique_ptr<WindowTreeHost> window_tree_host) { void EmbedRoot::OnEmbed(std::unique_ptr<WindowTreeHost> window_tree_host) {
focus_client_ =
std::make_unique<EmbeddedFocusClient>(window_tree_host->window());
window_tree_host_ = std::move(window_tree_host); window_tree_host_ = std::move(window_tree_host);
delegate_->OnEmbed(window()); delegate_->OnEmbed(window());
} }
......
...@@ -20,6 +20,10 @@ class Window; ...@@ -20,6 +20,10 @@ class Window;
class WindowTreeClient; class WindowTreeClient;
class WindowTreeHost; class WindowTreeHost;
namespace client {
class FocusClient;
}
// EmbedRoot represents a secondary embedding from the perspective of the // EmbedRoot represents a secondary embedding from the perspective of the
// embedded client. More specifically an EmbedRoot allows a remote client to // embedded client. More specifically an EmbedRoot allows a remote client to
// embed this client in one of the remote client's Windows. // embed this client in one of the remote client's Windows.
...@@ -41,6 +45,7 @@ class AURA_EXPORT EmbedRoot { ...@@ -41,6 +45,7 @@ class AURA_EXPORT EmbedRoot {
private: private:
friend class WindowTreeClient; friend class WindowTreeClient;
friend class WindowTreeClientPrivate;
EmbedRoot(WindowTreeClient* window_tree_client, EmbedRoot(WindowTreeClient* window_tree_client,
EmbedRootDelegate* delegate, EmbedRootDelegate* delegate,
...@@ -61,6 +66,8 @@ class AURA_EXPORT EmbedRoot { ...@@ -61,6 +66,8 @@ class AURA_EXPORT EmbedRoot {
base::UnguessableToken token_; base::UnguessableToken token_;
std::unique_ptr<client::FocusClient> focus_client_;
std::unique_ptr<WindowTreeHost> window_tree_host_; std::unique_ptr<WindowTreeHost> window_tree_host_;
base::WeakPtrFactory<EmbedRoot> weak_factory_; base::WeakPtrFactory<EmbedRoot> weak_factory_;
......
...@@ -27,7 +27,7 @@ namespace client { ...@@ -27,7 +27,7 @@ namespace client {
class FocusClient; class FocusClient;
} }
// FocusSynchronizer is resonsible for keeping focus in sync between aura // FocusSynchronizer is responsible for keeping focus in sync between aura
// and the mus server. FocusSynchronizer may be configured in two distinct // and the mus server. FocusSynchronizer may be configured in two distinct
// ways: // ways:
// . SetSingletonFocusClient(). Use this when a single FocusClient is shared // . SetSingletonFocusClient(). Use this when a single FocusClient is shared
......
...@@ -366,8 +366,7 @@ void WindowTreeClient::Embed(Window* window, ...@@ -366,8 +366,7 @@ void WindowTreeClient::Embed(Window* window,
void WindowTreeClient::ScheduleEmbed( void WindowTreeClient::ScheduleEmbed(
ui::mojom::WindowTreeClientPtr client, ui::mojom::WindowTreeClientPtr client,
base::OnceCallback<void(const base::UnguessableToken&)> callback) { base::OnceCallback<void(const base::UnguessableToken&)> callback) {
tree_->ScheduleEmbed(std::move(client), tree_->ScheduleEmbed(std::move(client), std::move(callback));
base::AdaptCallbackForRepeating(std::move(callback)));
} }
void WindowTreeClient::EmbedUsingToken( void WindowTreeClient::EmbedUsingToken(
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "ui/aura/client/transient_window_client.h" #include "ui/aura/client/transient_window_client.h"
#include "ui/aura/mus/capture_synchronizer.h" #include "ui/aura/mus/capture_synchronizer.h"
#include "ui/aura/mus/client_surface_embedder.h" #include "ui/aura/mus/client_surface_embedder.h"
#include "ui/aura/mus/embed_root.h"
#include "ui/aura/mus/embed_root_delegate.h"
#include "ui/aura/mus/focus_synchronizer.h" #include "ui/aura/mus/focus_synchronizer.h"
#include "ui/aura/mus/property_converter.h" #include "ui/aura/mus/property_converter.h"
#include "ui/aura/mus/window_mus.h" #include "ui/aura/mus/window_mus.h"
...@@ -2966,4 +2968,33 @@ TEST_F(WindowTreeClientWmTestHighDPI, ObservedPointerEvents) { ...@@ -2966,4 +2968,33 @@ TEST_F(WindowTreeClientWmTestHighDPI, ObservedPointerEvents) {
last_event->root_location()); last_event->root_location());
} }
namespace {
class TestEmbedRootDelegate : public EmbedRootDelegate {
public:
TestEmbedRootDelegate() = default;
~TestEmbedRootDelegate() override = default;
// EmbedRootDelegate:
void OnEmbedTokenAvailable(const base::UnguessableToken& token) override {}
void OnEmbed(Window* window) override {}
void OnUnembed() override {}
private:
DISALLOW_COPY_AND_ASSIGN(TestEmbedRootDelegate);
};
} // namespace
// Verifies we don't crash when focus changes to a window in an EmbedRoot.
TEST_F(WindowTreeClientClientTest, ChangeFocusInEmbedRootWindow) {
TestEmbedRootDelegate embed_root_delegate;
std::unique_ptr<EmbedRoot> embed_root =
window_tree_client_impl()->CreateEmbedRoot(&embed_root_delegate);
WindowTreeClientPrivate(window_tree_client_impl())
.CallOnEmbedFromToken(embed_root.get());
ASSERT_TRUE(embed_root->window());
window_tree_client()->OnWindowFocused(server_id(embed_root->window()));
}
} // namespace aura } // namespace aura
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "ui/aura/test/mus/window_tree_client_private.h" #include "ui/aura/test/mus/window_tree_client_private.h"
#include "base/unguessable_token.h"
#include "ui/aura/mus/embed_root.h"
#include "ui/aura/mus/in_flight_change.h" #include "ui/aura/mus/in_flight_change.h"
#include "ui/aura/mus/window_port_mus.h" #include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/mus/window_tree_client.h" #include "ui/aura/mus/window_tree_client.h"
...@@ -12,6 +14,11 @@ ...@@ -12,6 +14,11 @@
#include "ui/display/display.h" #include "ui/display/display.h"
namespace aura { namespace aura {
namespace {
constexpr int64_t kDisplayId = 1;
} // namespace
WindowTreeClientPrivate::WindowTreeClientPrivate( WindowTreeClientPrivate::WindowTreeClientPrivate(
WindowTreeClient* tree_client_impl) WindowTreeClient* tree_client_impl)
...@@ -34,14 +41,10 @@ WindowTreeClientPrivate::CreateWindowTreeClient( ...@@ -34,14 +41,10 @@ WindowTreeClientPrivate::CreateWindowTreeClient(
} }
void WindowTreeClientPrivate::OnEmbed(ui::mojom::WindowTree* window_tree) { void WindowTreeClientPrivate::OnEmbed(ui::mojom::WindowTree* window_tree) {
ui::mojom::WindowDataPtr root_data(ui::mojom::WindowData::New());
root_data->parent_id = 0;
root_data->window_id = next_window_id_++;
root_data->visible = true;
const int64_t display_id = 1;
const ui::Id focused_window_id = 0; const ui::Id focused_window_id = 0;
tree_client_impl_->OnEmbedImpl(window_tree, std::move(root_data), display_id, tree_client_impl_->OnEmbedImpl(window_tree, CreateWindowDataForEmbed(),
focused_window_id, true, base::nullopt); kDisplayId, focused_window_id, true,
base::nullopt);
} }
WindowTreeHostMus* WindowTreeClientPrivate::CallWmNewDisplayAdded( WindowTreeHostMus* WindowTreeClientPrivate::CallWmNewDisplayAdded(
...@@ -86,6 +89,14 @@ void WindowTreeClientPrivate::CallOnConnect() { ...@@ -86,6 +89,14 @@ void WindowTreeClientPrivate::CallOnConnect() {
tree_client_impl_->OnConnect(); tree_client_impl_->OnConnect();
} }
void WindowTreeClientPrivate::CallOnEmbedFromToken(EmbedRoot* embed_root) {
embed_root->OnScheduledEmbedForExistingClient(
base::UnguessableToken::Create());
tree_client_impl_->OnEmbedFromToken(embed_root->token(),
CreateWindowDataForEmbed(), kDisplayId,
base::Optional<viz::LocalSurfaceId>());
}
WindowTreeHostMusInitParams WindowTreeHostMusInitParams
WindowTreeClientPrivate::CallCreateInitParamsForNewDisplay() { WindowTreeClientPrivate::CallCreateInitParamsForNewDisplay() {
return tree_client_impl_->CreateInitParamsForNewDisplay(); return tree_client_impl_->CreateInitParamsForNewDisplay();
...@@ -131,4 +142,12 @@ void WindowTreeClientPrivate::WaitForInitialDisplays() { ...@@ -131,4 +142,12 @@ void WindowTreeClientPrivate::WaitForInitialDisplays() {
tree_client_impl_->WaitForInitialDisplays(); tree_client_impl_->WaitForInitialDisplays();
} }
ui::mojom::WindowDataPtr WindowTreeClientPrivate::CreateWindowDataForEmbed() {
ui::mojom::WindowDataPtr root_data(ui::mojom::WindowData::New());
root_data->parent_id = 0;
root_data->window_id = next_window_id_++;
root_data->visible = true;
return root_data;
}
} // namespace aura } // namespace aura
...@@ -28,6 +28,7 @@ class WindowTree; ...@@ -28,6 +28,7 @@ class WindowTree;
namespace aura { namespace aura {
class EmbedRoot;
class Window; class Window;
class WindowManagerDelegate; class WindowManagerDelegate;
class WindowMus; class WindowMus;
...@@ -66,6 +67,10 @@ class WindowTreeClientPrivate { ...@@ -66,6 +67,10 @@ class WindowTreeClientPrivate {
void CallOnConnect(); void CallOnConnect();
// Simulates the EmbedRoot receiving the token from the WindowTree and then
// the WindowTree calling OnEmbedFromToken().
void CallOnEmbedFromToken(EmbedRoot* embed_root);
WindowTreeHostMusInitParams CallCreateInitParamsForNewDisplay(); WindowTreeHostMusInitParams CallCreateInitParamsForNewDisplay();
// Sets the WindowTree. // Sets the WindowTree.
...@@ -87,6 +92,8 @@ class WindowTreeClientPrivate { ...@@ -87,6 +92,8 @@ class WindowTreeClientPrivate {
void WaitForInitialDisplays(); void WaitForInitialDisplays();
private: private:
ui::mojom::WindowDataPtr CreateWindowDataForEmbed();
WindowTreeClient* tree_client_impl_; WindowTreeClient* tree_client_impl_;
uint16_t next_window_id_ = 1u; uint16_t next_window_id_ = 1u;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment