summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky <sky@chromium.org>2016-03-25 16:30:50 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-25 23:33:10 +0000
commit19019f27a62f561909f0ec733510bacbd74b374c (patch)
treed56084fd448cecd5d30e8796a8aaf9111a51ae1b
parentc4f0abb4666f3296485e53fd5ede71f161938048 (diff)
downloadchromium_src-19019f27a62f561909f0ec733510bacbd74b374c.zip
chromium_src-19019f27a62f561909f0ec733510bacbd74b374c.tar.gz
chromium_src-19019f27a62f561909f0ec733510bacbd74b374c.tar.bz2
Routes setting focus through WindowServer so it can notify other displays
This way we only have one Display with focus. BUG=none TEST=none R=ben@chromium.org Review URL: https://codereview.chromium.org/1833873004 Cr-Commit-Position: refs/heads/master@{#383403}
-rw-r--r--components/mus/mus_app.cc10
-rw-r--r--components/mus/mus_app.h5
-rw-r--r--components/mus/ws/display.cc19
-rw-r--r--components/mus/ws/display.h8
-rw-r--r--components/mus/ws/display_unittest.cc106
-rw-r--r--components/mus/ws/test_utils.cc83
-rw-r--r--components/mus/ws/test_utils.h46
-rw-r--r--components/mus/ws/window_server.cc47
-rw-r--r--components/mus/ws/window_server.h15
-rw-r--r--components/mus/ws/window_server_delegate.cc11
-rw-r--r--components/mus/ws/window_server_delegate.h24
-rw-r--r--components/mus/ws/window_tree.cc45
-rw-r--r--components/mus/ws/window_tree.h1
-rw-r--r--components/mus/ws/window_tree_unittest.cc20
14 files changed, 326 insertions, 114 deletions
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index 6d15e5b..3d0edfa 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -184,16 +184,6 @@ void MandolineUIServicesApp::OnNoMoreDisplays() {
base::MessageLoop::current()->QuitWhenIdle();
}
-scoped_ptr<ws::WindowTreeBinding>
-MandolineUIServicesApp::CreateWindowTreeBindingForEmbedAtWindow(
- ws::WindowServer* window_server,
- ws::WindowTree* tree,
- mojom::WindowTreeRequest tree_request,
- mojom::WindowTreeClientPtr client) {
- return make_scoped_ptr(new ws::DefaultWindowTreeBinding(
- tree, window_server, std::move(tree_request), std::move(client)));
-}
-
void MandolineUIServicesApp::CreateDefaultDisplays() {
// Display manages its own lifetime.
ws::Display* host_impl =
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h
index c66267f..d013784 100644
--- a/components/mus/mus_app.h
+++ b/components/mus/mus_app.h
@@ -79,11 +79,6 @@ class MandolineUIServicesApp
// WindowServerDelegate:
void OnFirstDisplayReady() override;
void OnNoMoreDisplays() override;
- scoped_ptr<ws::WindowTreeBinding> CreateWindowTreeBindingForEmbedAtWindow(
- ws::WindowServer* window_server,
- ws::WindowTree* tree,
- mojom::WindowTreeRequest tree_request,
- mojom::WindowTreeClientPtr client) override;
void CreateDefaultDisplays() override;
// mojo::InterfaceFactory<mojom::DisplayManager> implementation.
diff --git a/components/mus/ws/display.cc b/components/mus/ws/display.cc
index a8c9229..f8582f6 100644
--- a/components/mus/ws/display.cc
+++ b/components/mus/ws/display.cc
@@ -42,7 +42,11 @@ Display::~Display() {
window_server_->window_manager_factory_registry()->RemoveObserver(this);
- DestroyFocusController();
+ if (!focus_controller_) {
+ focus_controller_->RemoveObserver(this);
+ focus_controller_.reset();
+ }
+
for (ServerWindow* window : windows_needing_frame_destruction_)
window->RemoveObserver(this);
@@ -154,11 +158,10 @@ const WindowManagerState* Display::GetActiveWindowManagerState() const {
}
void Display::SetFocusedWindow(ServerWindow* new_focused_window) {
- // TODO(sky): this is wrong. Focus is global, not per Display.
ServerWindow* old_focused_window = focus_controller_->GetFocusedWindow();
if (old_focused_window == new_focused_window)
return;
- DCHECK(root_window()->Contains(new_focused_window));
+ DCHECK(!new_focused_window || root_window()->Contains(new_focused_window));
focus_controller_->SetFocusedWindow(new_focused_window);
}
@@ -166,12 +169,10 @@ ServerWindow* Display::GetFocusedWindow() {
return focus_controller_->GetFocusedWindow();
}
-void Display::DestroyFocusController() {
- if (!focus_controller_)
- return;
-
- focus_controller_->RemoveObserver(this);
- focus_controller_.reset();
+void Display::ActivateNextWindow() {
+ // TODO(sky): this is wrong, needs to figure out the next window to activate
+ // and then route setting through WindowServer.
+ focus_controller_->ActivateNextWindow();
}
void Display::AddActivationParent(ServerWindow* window) {
diff --git a/components/mus/ws/display.h b/components/mus/ws/display.h
index ad1e8e1..b83c11d 100644
--- a/components/mus/ws/display.h
+++ b/components/mus/ws/display.h
@@ -113,10 +113,14 @@ class Display : public PlatformDisplayDelegate,
return window_manager_state_map_.size();
}
+ // TODO(sky): this should only be called by WindowServer, move to interface
+ // used by WindowServer.
void SetFocusedWindow(ServerWindow* window);
+ // NOTE: this returns the focused window only if the focused window is in this
+ // display. If this returns null focus may be in another display.
ServerWindow* GetFocusedWindow();
- void DestroyFocusController();
- FocusController* focus_controller() { return focus_controller_.get(); }
+
+ void ActivateNextWindow();
void AddActivationParent(ServerWindow* window);
void RemoveActivationParent(ServerWindow* window);
diff --git a/components/mus/ws/display_unittest.cc b/components/mus/ws/display_unittest.cc
index 7b62e5f..5d54baa 100644
--- a/components/mus/ws/display_unittest.cc
+++ b/components/mus/ws/display_unittest.cc
@@ -46,6 +46,12 @@ class TestWindowManagerFactory : public mojom::WindowManagerFactory {
DISALLOW_COPY_AND_ASSIGN(TestWindowManagerFactory);
};
+ClientWindowId ClientWindowIdForFirstRoot(WindowTree* tree) {
+ if (tree->roots().empty())
+ return ClientWindowId();
+ return ClientWindowIdForWindow(tree, *tree->roots().begin());
+}
+
} // namespace
// -----------------------------------------------------------------------------
@@ -217,17 +223,11 @@ TEST_F(DisplayTest, SetCaptureFromWindowManager) {
display->GetWindowManagerStateForUser(kTestId2);
ASSERT_TRUE(wms_for_id2);
EXPECT_FALSE(wms_for_id2->IsActive());
- ClientWindowId root_client_id;
// Create a child of the root that we can set capture on.
WindowTree* tree = wms_for_id2->tree();
- const ServerWindow* root = *tree->roots().begin();
- ASSERT_TRUE(tree->IsWindowKnown(root, &root_client_id));
- ClientWindowId child_window_id(
- WindowIdToTransportId(WindowId(tree->id(), 101)));
- ASSERT_TRUE(tree->NewWindow(child_window_id, ServerWindow::Properties()));
- ASSERT_TRUE(tree->SetWindowVisibility(child_window_id, true));
- ASSERT_TRUE(tree->AddWindow(root_client_id, child_window_id));
+ ClientWindowId child_window_id;
+ ASSERT_TRUE(NewWindowInTree(tree, &child_window_id));
WindowTreeTestApi(tree).EnableCapture();
@@ -240,6 +240,96 @@ TEST_F(DisplayTest, SetCaptureFromWindowManager) {
EXPECT_TRUE(tree->SetCapture(child_window_id));
}
+TEST_F(DisplayTest, FocusFailsForInactiveUser) {
+ window_server_delegate_.set_num_displays_to_create(1);
+ const UserId kTestId1 = "20";
+ const UserId kTestId2 = "201";
+ WindowManagerFactoryRegistryTestApi(
+ window_server_->window_manager_factory_registry())
+ .AddService(kTestId1, &test_window_manager_factory_);
+ TestWindowTreeClient* window_tree_client1 =
+ window_server_delegate_.last_client();
+ ASSERT_TRUE(window_tree_client1);
+ WindowManagerFactoryRegistryTestApi(
+ window_server_->window_manager_factory_registry())
+ .AddService(kTestId2, &test_window_manager_factory_);
+ window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
+ DisplayManager* display_manager = window_server_->display_manager();
+ ASSERT_EQ(1u, display_manager->displays().size());
+ Display* display = *display_manager->displays().begin();
+ WindowManagerState* wms_for_id2 =
+ display->GetWindowManagerStateForUser(kTestId2);
+ ASSERT_TRUE(wms_for_id2);
+ EXPECT_FALSE(wms_for_id2->IsActive());
+
+ // Focus should fail for windows in inactive window managers.
+ EXPECT_FALSE(wms_for_id2->tree()->SetFocus(
+ ClientWindowIdForFirstRoot(wms_for_id2->tree())));
+
+ // Focus should succeed for the active window manager.
+ WindowManagerState* wms_for_id1 =
+ display->GetWindowManagerStateForUser(kTestId1);
+ ASSERT_TRUE(wms_for_id1);
+ EXPECT_TRUE(wms_for_id1->IsActive());
+ EXPECT_TRUE(wms_for_id1->tree()->SetFocus(
+ ClientWindowIdForFirstRoot(wms_for_id1->tree())));
+}
+
+// Verifies clients are notified of focus changes in different displays.
+TEST_F(DisplayTest, CrossDisplayFocus) {
+ window_server_delegate_.set_num_displays_to_create(2);
+ const UserId kTestId1 = "20";
+ WindowManagerFactoryRegistryTestApi(
+ window_server_->window_manager_factory_registry())
+ .AddService(kTestId1, &test_window_manager_factory_);
+ window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
+ ASSERT_EQ(2u, window_server_delegate_.bindings()->size());
+ TestWindowTreeBinding* window_tree_binding1 =
+ (*window_server_delegate_.bindings())[0];
+ Display* display1 = window_tree_binding1->tree()->GetDisplay(
+ FirstRoot(window_tree_binding1->tree()));
+ WindowManagerState* display1_wms =
+ display1->GetWindowManagerStateForUser(kTestId1);
+ TestWindowTreeBinding* window_tree_binding2 =
+ (*window_server_delegate_.bindings())[1];
+ Display* display2 = window_tree_binding2->tree()->GetDisplay(
+ FirstRoot(window_tree_binding2->tree()));
+ WindowManagerState* display2_wms =
+ display2->GetWindowManagerStateForUser(kTestId1);
+
+ // Create children in both displays.
+ ClientWindowId child1_id;
+ ServerWindow* child1 = NewWindowInTree(display1_wms->tree(), &child1_id);
+ ASSERT_TRUE(child1);
+ child1->set_can_focus(true);
+ ClientWindowId child2_id;
+ ServerWindow* child2 = NewWindowInTree(display2_wms->tree(), &child2_id);
+ ASSERT_TRUE(child2);
+ child2->set_can_focus(true);
+
+ display1->AddActivationParent(FirstRoot(display1_wms->tree()));
+ display2->AddActivationParent(FirstRoot(display2_wms->tree()));
+ FirstRoot(display1_wms->tree())->set_can_focus(true);
+ FirstRoot(display2_wms->tree())->set_can_focus(true);
+ EXPECT_TRUE(display1_wms->tree()->SetFocus(child1_id));
+ EXPECT_EQ(child1, display1->GetFocusedWindow());
+ EXPECT_FALSE(display2->GetFocusedWindow());
+ window_tree_binding1->client()->tracker()->changes()->clear();
+ window_tree_binding2->client()->tracker()->changes()->clear();
+ // Moving focus to display2 should result in notifying display1.
+ EXPECT_TRUE(display2_wms->tree()->SetFocus(child2_id));
+ EXPECT_EQ("Focused id=null",
+ SingleChangeToDescription(
+ *window_tree_binding1->client()->tracker()->changes()));
+ EXPECT_EQ("", SingleChangeToDescription(
+ *window_tree_binding2->client()->tracker()->changes()));
+ EXPECT_TRUE(window_tree_binding2->client()->tracker()->changes()->empty());
+ window_tree_binding1->client()->tracker()->changes()->clear();
+ window_tree_binding2->client()->tracker()->changes()->clear();
+ EXPECT_FALSE(display1->GetFocusedWindow());
+ EXPECT_EQ(child2, display2->GetFocusedWindow());
+}
+
} // namespace test
} // namespace ws
} // namespace mus
diff --git a/components/mus/ws/test_utils.cc b/components/mus/ws/test_utils.cc
index 4201f94..673af9f 100644
--- a/components/mus/ws/test_utils.cc
+++ b/components/mus/ws/test_utils.cc
@@ -61,6 +61,17 @@ class TestPlatformDisplay : public PlatformDisplay {
DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplay);
};
+ClientWindowId NextUnusedClientWindowId(WindowTree* tree) {
+ ClientWindowId client_id;
+ for (ConnectionSpecificId id = 1;; ++id) {
+ // Used the id of the connection in the upper bits to simplify things.
+ const ClientWindowId client_id =
+ ClientWindowId(WindowIdToTransportId(WindowId(tree->id(), id)));
+ if (!tree->GetWindowByClientId(client_id))
+ return client_id;
+ }
+}
+
} // namespace
// WindowManagerFactoryRegistryTestApi ----------------------------------------
@@ -262,12 +273,14 @@ void TestWindowTreeClient::GetWindowManager(
// TestWindowTreeBinding ------------------------------------------------------
-TestWindowTreeBinding::TestWindowTreeBinding() : WindowTreeBinding(&client_) {}
+TestWindowTreeBinding::TestWindowTreeBinding(WindowTree* tree)
+ : WindowTreeBinding(&client_), tree_(tree) {}
TestWindowTreeBinding::~TestWindowTreeBinding() {}
mojom::WindowManager* TestWindowTreeBinding::GetWindowManager() {
- NOTREACHED();
- return nullptr;
+ if (!window_manager_.get())
+ window_manager_.reset(new TestWindowManager);
+ return window_manager_.get();
}
void TestWindowTreeBinding::SetIncomingMethodCallProcessingPaused(bool paused) {
is_paused_ = paused;
@@ -278,18 +291,25 @@ void TestWindowTreeBinding::SetIncomingMethodCallProcessingPaused(bool paused) {
TestWindowServerDelegate::TestWindowServerDelegate() {}
TestWindowServerDelegate::~TestWindowServerDelegate() {}
+Display* TestWindowServerDelegate::AddDisplay() {
+ // Display manages its own lifetime.
+ Display* display = new Display(window_server_, PlatformDisplayInitParams());
+ display->Init(nullptr);
+ return display;
+}
+
void TestWindowServerDelegate::OnNoMoreDisplays() {
got_on_no_more_displays_ = true;
}
-scoped_ptr<WindowTreeBinding>
-TestWindowServerDelegate::CreateWindowTreeBindingForEmbedAtWindow(
+scoped_ptr<WindowTreeBinding> TestWindowServerDelegate::CreateWindowTreeBinding(
+ BindingType type,
ws::WindowServer* window_server,
ws::WindowTree* tree,
- mojom::WindowTreeRequest tree_request,
- mojom::WindowTreeClientPtr client) {
- scoped_ptr<TestWindowTreeBinding> binding(new TestWindowTreeBinding);
- last_binding_ = binding.get();
+ mojom::WindowTreeRequest* tree_request,
+ mojom::WindowTreeClientPtr* client) {
+ scoped_ptr<TestWindowTreeBinding> binding(new TestWindowTreeBinding(tree));
+ bindings_.push_back(binding.get());
return std::move(binding);
}
@@ -297,11 +317,46 @@ void TestWindowServerDelegate::CreateDefaultDisplays() {
DCHECK(num_displays_to_create_);
DCHECK(window_server_);
- for (int i = 0; i < num_displays_to_create_; ++i) {
- // Display manages its own lifetime.
- Display* display = new Display(window_server_, PlatformDisplayInitParams());
- display->Init(nullptr);
- }
+ for (int i = 0; i < num_displays_to_create_; ++i)
+ AddDisplay();
+}
+
+ServerWindow* FirstRoot(WindowTree* tree) {
+ return tree->roots().size() == 1u
+ ? tree->GetWindow((*tree->roots().begin())->id())
+ : nullptr;
+}
+
+ClientWindowId FirstRootId(WindowTree* tree) {
+ ServerWindow* first_root = FirstRoot(tree);
+ return first_root ? ClientWindowIdForWindow(tree, first_root)
+ : ClientWindowId();
+}
+
+ClientWindowId ClientWindowIdForWindow(WindowTree* tree,
+ const ServerWindow* window) {
+ ClientWindowId client_window_id;
+ // If window isn't known we'll return 0, which should then error out.
+ tree->IsWindowKnown(window, &client_window_id);
+ return client_window_id;
+}
+
+ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id) {
+ ServerWindow* parent = FirstRoot(tree);
+ if (!parent)
+ return nullptr;
+ ClientWindowId parent_client_id;
+ if (!tree->IsWindowKnown(parent, &parent_client_id))
+ return nullptr;
+ ClientWindowId client_window_id = NextUnusedClientWindowId(tree);
+ if (!tree->NewWindow(client_window_id, ServerWindow::Properties()))
+ return nullptr;
+ if (!tree->SetWindowVisibility(client_window_id, true))
+ return nullptr;
+ if (!tree->AddWindow(parent_client_id, client_window_id))
+ return nullptr;
+ *client_id = client_window_id;
+ return tree->GetWindowByClientId(client_window_id);
}
} // namespace test
diff --git a/components/mus/ws/test_utils.h b/components/mus/ws/test_utils.h
index 6366ce4..fd6c032 100644
--- a/components/mus/ws/test_utils.h
+++ b/components/mus/ws/test_utils.h
@@ -7,6 +7,8 @@
#include <stdint.h>
+#include <vector>
+
#include "components/mus/public/interfaces/display.mojom.h"
#include "components/mus/public/interfaces/window_tree.mojom.h"
#include "components/mus/ws/display.h"
@@ -303,9 +305,10 @@ class TestWindowTreeClient : public mus::mojom::WindowTreeClient {
// WindowTreeBinding implementation that vends TestWindowTreeBinding.
class TestWindowTreeBinding : public WindowTreeBinding {
public:
- TestWindowTreeBinding();
+ explicit TestWindowTreeBinding(WindowTree* tree);
~TestWindowTreeBinding() override;
+ WindowTree* tree() { return tree_; }
TestWindowTreeClient* client() { return &client_; }
bool is_paused() const { return is_paused_; }
@@ -315,8 +318,10 @@ class TestWindowTreeBinding : public WindowTreeBinding {
void SetIncomingMethodCallProcessingPaused(bool paused) override;
private:
+ WindowTree* tree_;
TestWindowTreeClient client_;
bool is_paused_ = false;
+ scoped_ptr<TestWindowManager> window_manager_;
DISALLOW_COPY_AND_ASSIGN(TestWindowTreeBinding);
};
@@ -338,33 +343,60 @@ class TestWindowServerDelegate : public WindowServerDelegate {
}
TestWindowTreeClient* last_client() {
- return last_binding_ ? last_binding_->client() : nullptr;
+ return last_binding() ? last_binding()->client() : nullptr;
+ }
+ TestWindowTreeBinding* last_binding() {
+ return bindings_.empty() ? nullptr : bindings_.back();
}
- TestWindowTreeBinding* last_binding() { return last_binding_; }
+
+ std::vector<TestWindowTreeBinding*>* bindings() { return &bindings_; }
bool got_on_no_more_displays() const { return got_on_no_more_displays_; }
+ Display* AddDisplay();
+
// WindowServerDelegate:
void OnNoMoreDisplays() override;
- scoped_ptr<WindowTreeBinding> CreateWindowTreeBindingForEmbedAtWindow(
+ scoped_ptr<WindowTreeBinding> CreateWindowTreeBinding(
+ BindingType type,
ws::WindowServer* window_server,
ws::WindowTree* tree,
- mojom::WindowTreeRequest tree_request,
- mojom::WindowTreeClientPtr client) override;
+ mojom::WindowTreeRequest* tree_request,
+ mojom::WindowTreeClientPtr* client) override;
void CreateDefaultDisplays() override;
private:
// If CreateDefaultDisplays() this is the number of Displays that are
// created. The default is 0, which results in a DCHECK.
int num_displays_to_create_ = 0;
- TestWindowTreeBinding* last_binding_ = nullptr;
Display* display_ = nullptr;
WindowServer* window_server_ = nullptr;
bool got_on_no_more_displays_ = false;
+ // All TestWindowTreeBinding objects created via CreateWindowTreeBinding.
+ // These are owned by the corresponding WindowTree.
+ std::vector<TestWindowTreeBinding*> bindings_;
DISALLOW_COPY_AND_ASSIGN(TestWindowServerDelegate);
};
+// -----------------------------------------------------------------------------
+
+// Returns the first and only root of |tree|. If |tree| has zero or more than
+// one root returns null.
+ServerWindow* FirstRoot(WindowTree* tree);
+
+// Returns the ClientWindowId of the first root of |tree|, or an empty
+// ClientWindowId if |tree| has zero or more than one root.
+ClientWindowId FirstRootId(WindowTree* tree);
+
+// Returns |tree|s ClientWindowId for |window|.
+ClientWindowId ClientWindowIdForWindow(WindowTree* tree,
+ const ServerWindow* window);
+
+// Creates a new visible window as a child of the single root of |tree|.
+// |client_id| set to the ClientWindowId of the new window.
+ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id);
+
} // namespace test
} // namespace ws
} // namespace mus
diff --git a/components/mus/ws/window_server.cc b/components/mus/ws/window_server.cc
index 3bfadc2..fdef43c 100644
--- a/components/mus/ws/window_server.cc
+++ b/components/mus/ws/window_server.cc
@@ -77,9 +77,14 @@ WindowTree* WindowServer::EmbedAtWindow(
WindowTree* tree = tree_ptr.get();
mojom::WindowTreePtr window_tree_ptr;
- scoped_ptr<WindowTreeBinding> binding =
- delegate_->CreateWindowTreeBindingForEmbedAtWindow(
- this, tree, GetProxy(&window_tree_ptr), std::move(client));
+ mojom::WindowTreeRequest window_tree_request = GetProxy(&window_tree_ptr);
+ scoped_ptr<WindowTreeBinding> binding = delegate_->CreateWindowTreeBinding(
+ WindowServerDelegate::BindingType::EMBED, this, tree,
+ &window_tree_request, &client);
+ if (!binding) {
+ binding.reset(new ws::DefaultWindowTreeBinding(
+ tree, this, std::move(window_tree_request), std::move(client)));
+ }
AddTree(std::move(tree_ptr), std::move(binding), std::move(window_tree_ptr));
OnTreeMessagedClient(tree->id());
@@ -107,9 +112,17 @@ WindowTree* WindowServer::CreateTreeForWindowManager(
scoped_ptr<WindowTree> tree_ptr(new WindowTree(
this, user_id, root, make_scoped_ptr(new WindowManagerAccessPolicy)));
WindowTree* tree = tree_ptr.get();
- scoped_ptr<DefaultWindowTreeBinding> binding(new DefaultWindowTreeBinding(
- tree_ptr.get(), this, std::move(tree_client)));
- mojom::WindowTreePtr window_tree_ptr = binding->CreateInterfacePtrAndBind();
+ mojom::WindowTreePtr window_tree_ptr;
+ mojom::WindowTreeRequest tree_request;
+ scoped_ptr<WindowTreeBinding> binding = delegate_->CreateWindowTreeBinding(
+ WindowServerDelegate::BindingType::WINDOW_MANAGER, this, tree,
+ &tree_request, &tree_client);
+ if (!binding) {
+ DefaultWindowTreeBinding* default_binding = new DefaultWindowTreeBinding(
+ tree_ptr.get(), this, std::move(tree_client));
+ binding.reset(default_binding);
+ window_tree_ptr = default_binding->CreateInterfacePtrAndBind();
+ }
AddTree(std::move(tree_ptr), std::move(binding), std::move(window_tree_ptr));
tree->ConfigureWindowManager();
return tree;
@@ -224,6 +237,28 @@ void WindowServer::OnFirstWindowManagerFactorySet() {
delegate_->CreateDefaultDisplays();
}
+void WindowServer::SetFocusedWindow(ServerWindow* window) {
+ // TODO(sky): this should fail if there is modal dialog active and |window|
+ // is outside that.
+ Display* focused_display = nullptr;
+ for (Display* display : display_manager_->displays()) {
+ if (display->GetFocusedWindow()) {
+ focused_display = display;
+ break;
+ }
+ }
+ Display* display = display_manager_->GetDisplayContaining(window);
+ DCHECK(display); // It's assumed callers do validation before calling this.
+ display->SetFocusedWindow(window);
+ // If the focus actually changed, and focus was in another display, then we
+ // need to notify the previously focused display so that it cleans up state
+ // and notifies appropriately.
+ if (window && display->GetFocusedWindow() && display != focused_display &&
+ focused_display) {
+ focused_display->SetFocusedWindow(nullptr);
+ }
+}
+
uint32_t WindowServer::GenerateWindowManagerChangeId(
WindowTree* source,
uint32_t client_change_id) {
diff --git a/components/mus/ws/window_server.h b/components/mus/ws/window_server.h
index 9d3abe2..2f9aee1 100644
--- a/components/mus/ws/window_server.h
+++ b/components/mus/ws/window_server.h
@@ -103,6 +103,12 @@ class WindowServer : public ServerWindowDelegate,
: OperationType::NONE;
}
+ // Returns true if the specified connection issued the current operation.
+ bool IsOperationSource(ConnectionSpecificId tree_id) const {
+ return current_operation_ &&
+ current_operation_->source_tree_id() == tree_id;
+ }
+
// Invoked when a connection messages a client about the change. This is used
// to avoid sending ServerChangeIdAdvanced() unnecessarily.
void OnTreeMessagedClient(ConnectionSpecificId id);
@@ -128,6 +134,9 @@ class WindowServer : public ServerWindowDelegate,
return &window_manager_factory_registry_;
}
+ // Sets focus to the specified window.
+ void SetFocusedWindow(ServerWindow* window);
+
// Returns a change id for the window manager that is associated with
// |source| and |client_change_id|. When the window manager replies
// WindowManagerChangeCompleted() is called to obtain the original source
@@ -205,12 +214,6 @@ class WindowServer : public ServerWindowDelegate,
// Balances a call to PrepareForOperation().
void FinishOperation();
- // Returns true if the specified connection issued the current operation.
- bool IsOperationSource(ConnectionSpecificId tree_id) const {
- return current_operation_ &&
- current_operation_->source_tree_id() == tree_id;
- }
-
// Run in response to events which may cause us to change the native cursor.
void MaybeUpdateNativeCursor(ServerWindow* window);
diff --git a/components/mus/ws/window_server_delegate.cc b/components/mus/ws/window_server_delegate.cc
index 5886112..40c2751 100644
--- a/components/mus/ws/window_server_delegate.cc
+++ b/components/mus/ws/window_server_delegate.cc
@@ -4,10 +4,21 @@
#include "components/mus/ws/window_server_delegate.h"
+#include "components/mus/ws/window_tree_binding.h"
+
namespace mus {
namespace ws {
void WindowServerDelegate::OnFirstDisplayReady() {}
+scoped_ptr<WindowTreeBinding> WindowServerDelegate::CreateWindowTreeBinding(
+ BindingType type,
+ ws::WindowServer* window_server,
+ ws::WindowTree* tree,
+ mojom::WindowTreeRequest* tree_request,
+ mojom::WindowTreeClientPtr* client) {
+ return nullptr;
+}
+
} // namespace ws
} // namespace mus
diff --git a/components/mus/ws/window_server_delegate.h b/components/mus/ws/window_server_delegate.h
index e7ca4a2..05e32a0 100644
--- a/components/mus/ws/window_server_delegate.h
+++ b/components/mus/ws/window_server_delegate.h
@@ -32,22 +32,28 @@ class WindowTreeBinding;
class WindowServerDelegate {
public:
+ enum BindingType {
+ EMBED,
+ WINDOW_MANAGER,
+ };
+
+ // Called if no Displays have been created, but a WindowManagerFactory has
+ // been set.
+ virtual void CreateDefaultDisplays() = 0;
+
// Called once when the AcceleratedWidget of a Display is available.
virtual void OnFirstDisplayReady();
virtual void OnNoMoreDisplays() = 0;
- // Creates a WindowTreeBinding in response to Embed() calls on the
- // WindowServer.
- virtual scoped_ptr<WindowTreeBinding> CreateWindowTreeBindingForEmbedAtWindow(
+ // Creates a WindowTreeBinding. Default implementation returns null, which
+ // creates DefaultBinding.
+ virtual scoped_ptr<WindowTreeBinding> CreateWindowTreeBinding(
+ BindingType type,
ws::WindowServer* window_server,
ws::WindowTree* tree,
- mojom::WindowTreeRequest tree_request,
- mojom::WindowTreeClientPtr client) = 0;
-
- // Called if no Displays have been created, but a WindowManagerFactory has
- // been set.
- virtual void CreateDefaultDisplays() = 0;
+ mojom::WindowTreeRequest* tree_request,
+ mojom::WindowTreeClientPtr* client);
protected:
virtual ~WindowServerDelegate() {}
diff --git a/components/mus/ws/window_tree.cc b/components/mus/ws/window_tree.cc
index 5de526c..938fbd4 100644
--- a/components/mus/ws/window_tree.cc
+++ b/components/mus/ws/window_tree.cc
@@ -267,6 +267,23 @@ bool WindowTree::SetWindowVisibility(const ClientWindowId& window_id,
return true;
}
+bool WindowTree::SetFocus(const ClientWindowId& window_id) {
+ ServerWindow* window = GetWindowByClientId(window_id);
+ // TODO(beng): consider shifting non-policy drawn check logic to VTH's
+ // FocusController.
+ // TODO(sky): this doesn't work to clear focus. That is because if window is
+ // null, then |host| is null and we fail.
+ Display* display = GetDisplay(window);
+ if (!window || !display || !window->IsDrawn() || !window->can_focus() ||
+ !access_policy_->CanSetFocus(window)) {
+ return false;
+ }
+
+ Operation op(this, window_server_, OperationType::SET_FOCUS);
+ window_server_->SetFocusedWindow(window);
+ return true;
+}
+
bool WindowTree::Embed(const ClientWindowId& window_id,
mojom::WindowTreeClientPtr client) {
if (!client || !CanEmbed(window_id))
@@ -541,6 +558,10 @@ void WindowTree::ProcessCursorChanged(const ServerWindow* window,
void WindowTree::ProcessFocusChanged(const ServerWindow* old_focused_window,
const ServerWindow* new_focused_window) {
+ if (window_server_->current_operation_type() == OperationType::SET_FOCUS &&
+ window_server_->IsOperationSource(id_)) {
+ return;
+ }
const ServerWindow* window =
new_focused_window
? access_policy_->GetWindowForFocusChange(new_focused_window)
@@ -548,8 +569,6 @@ void WindowTree::ProcessFocusChanged(const ServerWindow* old_focused_window,
ClientWindowId client_window_id;
// If the window isn't known we'll supply null, which is ok.
IsWindowKnown(window, &client_window_id);
- // TODO(sky): this should only notify if this results in a change of focus
- // for the client.
client()->OnWindowFocused(client_window_id.id);
}
@@ -1203,20 +1222,8 @@ void WindowTree::Embed(Id transport_window_id,
}
void WindowTree::SetFocus(uint32_t change_id, Id transport_window_id) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- // TODO(beng): consider shifting non-policy drawn check logic to VTH's
- // FocusController.
- // TODO(sky): this doesn't work to clear focus. That is because if window is
- // null, then |host| is null and we fail.
- Display* display = GetDisplay(window);
- const bool success = window && window->IsDrawn() && window->can_focus() &&
- access_policy_->CanSetFocus(window) && display;
- if (success) {
- Operation op(this, window_server_, OperationType::SET_FOCUS);
- display->SetFocusedWindow(window);
- }
- client()->OnChangeCompleted(change_id, success);
+ client()->OnChangeCompleted(change_id,
+ SetFocus(ClientWindowId(transport_window_id)));
}
void WindowTree::SetCanFocus(Id transport_window_id, bool can_focus) {
@@ -1290,10 +1297,10 @@ void WindowTree::RemoveActivationParent(Id transport_window_id) {
}
void WindowTree::ActivateNextWindow() {
- Display* host = GetDisplayForWindowManager();
- if (!host)
+ Display* display = GetDisplayForWindowManager();
+ if (!display)
return;
- host->focus_controller()->ActivateNextWindow();
+ display->ActivateNextWindow();
}
void WindowTree::SetUnderlaySurfaceOffsetAndExtendedHitArea(
diff --git a/components/mus/ws/window_tree.h b/components/mus/ws/window_tree.h
index 95989a8..a47c6c4 100644
--- a/components/mus/ws/window_tree.h
+++ b/components/mus/ws/window_tree.h
@@ -138,6 +138,7 @@ class WindowTree : public mojom::WindowTree,
std::vector<const ServerWindow*> GetWindowTree(
const ClientWindowId& window_id) const;
bool SetWindowVisibility(const ClientWindowId& window_id, bool visible);
+ bool SetFocus(const ClientWindowId& window_id);
bool Embed(const ClientWindowId& window_id,
mojom::WindowTreeClientPtr client);
void DispatchInputEvent(ServerWindow* target, const ui::Event& event);
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index 72d9406..5018616 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -51,14 +51,6 @@ ClientWindowId BuildClientWindowId(WindowTree* tree,
return ClientWindowId(WindowIdToTransportId(WindowId(tree->id(), window_id)));
}
-ClientWindowId ClientWindowIdForWindow(WindowTree* tree,
- const ServerWindow* window) {
- ClientWindowId client_window_id;
- // If window isn't known we'll return 0, which should then error out.
- tree->IsWindowKnown(window, &client_window_id);
- return client_window_id;
-}
-
// -----------------------------------------------------------------------------
ui::PointerEvent CreatePointerDownEvent(int x, int y) {
@@ -91,16 +83,6 @@ ui::PointerEvent CreateMouseUpEvent(int x, int y) {
ui::EF_LEFT_MOUSE_BUTTON));
}
-const ServerWindow* FirstRoot(WindowTree* tree) {
- return tree->roots().size() == 1u ? *(tree->roots().begin()) : nullptr;
-}
-
-ClientWindowId FirstRootId(WindowTree* tree) {
- return tree->roots().size() == 1u
- ? ClientWindowIdForWindow(tree, *(tree->roots().begin()))
- : ClientWindowId();
-}
-
ServerWindow* GetCaptureWindow(Display* display) {
return display->GetActiveWindowManagerState()->capture_window();
}
@@ -170,7 +152,7 @@ class WindowTreeTest : public testing::Test {
TestWindowTreeBinding** binding) {
WindowTree* tree = new WindowTree(window_server_.get(), user_id, nullptr,
make_scoped_ptr(new DefaultAccessPolicy));
- *binding = new TestWindowTreeBinding;
+ *binding = new TestWindowTreeBinding(tree);
window_server_->AddTree(make_scoped_ptr(tree), make_scoped_ptr(*binding),
nullptr);
return tree;