From 19019f27a62f561909f0ec733510bacbd74b374c Mon Sep 17 00:00:00 2001 From: sky Date: Fri, 25 Mar 2016 16:30:50 -0700 Subject: 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} --- components/mus/mus_app.cc | 10 --- components/mus/mus_app.h | 5 -- components/mus/ws/display.cc | 19 ++--- components/mus/ws/display.h | 8 ++- components/mus/ws/display_unittest.cc | 106 +++++++++++++++++++++++++--- components/mus/ws/test_utils.cc | 83 ++++++++++++++++++---- components/mus/ws/test_utils.h | 46 ++++++++++-- components/mus/ws/window_server.cc | 47 ++++++++++-- components/mus/ws/window_server.h | 15 ++-- components/mus/ws/window_server_delegate.cc | 11 +++ components/mus/ws/window_server_delegate.h | 24 ++++--- components/mus/ws/window_tree.cc | 45 +++++++----- components/mus/ws/window_tree.h | 1 + components/mus/ws/window_tree_unittest.cc | 20 +----- 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 -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 CreateWindowTreeBindingForEmbedAtWindow( - ws::WindowServer* window_server, - ws::WindowTree* tree, - mojom::WindowTreeRequest tree_request, - mojom::WindowTreeClientPtr client) override; void CreateDefaultDisplays() override; // mojo::InterfaceFactory 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 -TestWindowServerDelegate::CreateWindowTreeBindingForEmbedAtWindow( +scoped_ptr TestWindowServerDelegate::CreateWindowTreeBinding( + BindingType type, ws::WindowServer* window_server, ws::WindowTree* tree, - mojom::WindowTreeRequest tree_request, - mojom::WindowTreeClientPtr client) { - scoped_ptr binding(new TestWindowTreeBinding); - last_binding_ = binding.get(); + mojom::WindowTreeRequest* tree_request, + mojom::WindowTreeClientPtr* client) { + scoped_ptr 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 +#include + #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 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* bindings() { return &bindings_; } bool got_on_no_more_displays() const { return got_on_no_more_displays_; } + Display* AddDisplay(); + // WindowServerDelegate: void OnNoMoreDisplays() override; - scoped_ptr CreateWindowTreeBindingForEmbedAtWindow( + scoped_ptr 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 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 binding = - delegate_->CreateWindowTreeBindingForEmbedAtWindow( - this, tree, GetProxy(&window_tree_ptr), std::move(client)); + mojom::WindowTreeRequest window_tree_request = GetProxy(&window_tree_ptr); + scoped_ptr 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 tree_ptr(new WindowTree( this, user_id, root, make_scoped_ptr(new WindowManagerAccessPolicy))); WindowTree* tree = tree_ptr.get(); - scoped_ptr 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 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 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 CreateWindowTreeBindingForEmbedAtWindow( + // Creates a WindowTreeBinding. Default implementation returns null, which + // creates DefaultBinding. + virtual scoped_ptr 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 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; -- cgit v1.1