blob: 2c2506cce2631ffbb41bbe6c255920c491cff816 [file] [log] [blame]
// Copyright 2016 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 <stdint.h>
#include <string>
#include "base/atomicops.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "components/mus/common/types.h"
#include "components/mus/common/util.h"
#include "components/mus/public/interfaces/window_tree.mojom.h"
#include "components/mus/surfaces/surfaces_state.h"
#include "components/mus/ws/display_binding.h"
#include "components/mus/ws/display_manager.h"
#include "components/mus/ws/ids.h"
#include "components/mus/ws/platform_display.h"
#include "components/mus/ws/platform_display_factory.h"
#include "components/mus/ws/platform_display_init_params.h"
#include "components/mus/ws/server_window.h"
#include "components/mus/ws/test_utils.h"
#include "components/mus/ws/window_manager_state.h"
#include "components/mus/ws/window_manager_window_tree_factory_set.h"
#include "components/mus/ws/window_server.h"
#include "components/mus/ws/window_server_delegate.h"
#include "components/mus/ws/window_tree.h"
#include "components/mus/ws/window_tree_binding.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
namespace mus {
namespace ws {
namespace test {
namespace {
class TestDisplayManagerObserver : public mojom::DisplayManagerObserver {
public:
TestDisplayManagerObserver() {}
~TestDisplayManagerObserver() override {}
std::string GetAndClearObserverCalls() {
std::string result;
std::swap(observer_calls_, result);
return result;
}
private:
void AddCall(const std::string& call) {
if (!observer_calls_.empty())
observer_calls_ += "\n";
observer_calls_ += call;
}
std::string DisplayIdsToString(
const mojo::Array<mojom::DisplayPtr>& displays) {
std::string display_ids;
for (const auto& display : displays) {
if (!display_ids.empty())
display_ids += " ";
display_ids += base::Int64ToString(display->id);
}
return display_ids;
}
// mojom::DisplayManagerObserver:
void OnDisplays(mojo::Array<mojom::DisplayPtr> displays) override {
AddCall("OnDisplays " + DisplayIdsToString(displays));
}
void OnDisplaysChanged(mojo::Array<mojom::DisplayPtr> displays) override {
AddCall("OnDisplaysChanged " + DisplayIdsToString(displays));
}
void OnDisplayRemoved(int64_t id) override {
AddCall("OnDisplayRemoved " + base::Int64ToString(id));
}
std::string observer_calls_;
DISALLOW_COPY_AND_ASSIGN(TestDisplayManagerObserver);
};
mojom::FrameDecorationValuesPtr CreateDefaultFrameDecorationValues() {
return mojom::FrameDecorationValues::New();
}
} // namespace
// -----------------------------------------------------------------------------
class UserDisplayManagerTest : public testing::Test {
public:
UserDisplayManagerTest()
: cursor_id_(0), platform_display_factory_(&cursor_id_) {}
~UserDisplayManagerTest() override {}
protected:
// testing::Test:
void SetUp() override {
PlatformDisplay::set_factory_for_testing(&platform_display_factory_);
window_server_.reset(new WindowServer(&window_server_delegate_,
scoped_refptr<SurfacesState>()));
window_server_delegate_.set_window_server(window_server_.get());
}
protected:
int32_t cursor_id_;
TestPlatformDisplayFactory platform_display_factory_;
TestWindowServerDelegate window_server_delegate_;
std::unique_ptr<WindowServer> window_server_;
base::MessageLoop message_loop_;
private:
DISALLOW_COPY_AND_ASSIGN(UserDisplayManagerTest);
};
TEST_F(UserDisplayManagerTest, OnlyNotifyWhenFrameDecorationsSet) {
window_server_delegate_.set_num_displays_to_create(1);
const UserId kUserId1 = "2";
TestDisplayManagerObserver display_manager_observer1;
DisplayManager* display_manager = window_server_->display_manager();
WindowManagerWindowTreeFactorySetTestApi(
window_server_->window_manager_window_tree_factory_set())
.Add(kUserId1);
UserDisplayManager* user_display_manager1 =
display_manager->GetUserDisplayManager(kUserId1);
ASSERT_TRUE(user_display_manager1);
UserDisplayManagerTestApi(user_display_manager1)
.SetTestObserver(&display_manager_observer1);
// Observer should not have been notified yet.
EXPECT_EQ(std::string(),
display_manager_observer1.GetAndClearObserverCalls());
// Set the frame decoration values, which should trigger sending immediately.
ASSERT_EQ(1u, display_manager->displays().size());
window_server_->window_manager_window_tree_factory_set()
->GetWindowManagerStateForUser(kUserId1)
->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
EXPECT_EQ("OnDisplays 1",
display_manager_observer1.GetAndClearObserverCalls());
UserDisplayManagerTestApi(user_display_manager1).SetTestObserver(nullptr);
}
TEST_F(UserDisplayManagerTest, AddObserverAfterFrameDecorationsSet) {
window_server_delegate_.set_num_displays_to_create(1);
const UserId kUserId1 = "2";
TestDisplayManagerObserver display_manager_observer1;
DisplayManager* display_manager = window_server_->display_manager();
WindowManagerWindowTreeFactorySetTestApi(
window_server_->window_manager_window_tree_factory_set())
.Add(kUserId1);
UserDisplayManager* user_display_manager1 =
display_manager->GetUserDisplayManager(kUserId1);
ASSERT_TRUE(user_display_manager1);
ASSERT_EQ(1u, display_manager->displays().size());
window_server_->window_manager_window_tree_factory_set()
->GetWindowManagerStateForUser(kUserId1)
->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
UserDisplayManagerTestApi(user_display_manager1)
.SetTestObserver(&display_manager_observer1);
EXPECT_EQ("OnDisplays 1",
display_manager_observer1.GetAndClearObserverCalls());
UserDisplayManagerTestApi(user_display_manager1).SetTestObserver(nullptr);
}
TEST_F(UserDisplayManagerTest, AddRemoveDisplay) {
window_server_delegate_.set_num_displays_to_create(1);
const UserId kUserId1 = "2";
TestDisplayManagerObserver display_manager_observer1;
DisplayManager* display_manager = window_server_->display_manager();
WindowManagerWindowTreeFactorySetTestApi(
window_server_->window_manager_window_tree_factory_set())
.Add(kUserId1);
UserDisplayManager* user_display_manager1 =
display_manager->GetUserDisplayManager(kUserId1);
ASSERT_TRUE(user_display_manager1);
ASSERT_EQ(1u, display_manager->displays().size());
window_server_->window_manager_window_tree_factory_set()
->GetWindowManagerStateForUser(kUserId1)
->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
UserDisplayManagerTestApi(user_display_manager1)
.SetTestObserver(&display_manager_observer1);
EXPECT_EQ("OnDisplays 1",
display_manager_observer1.GetAndClearObserverCalls());
// Add another display.
Display* display2 =
new Display(window_server_.get(), PlatformDisplayInitParams());
display2->Init(nullptr);
// Observer should be notified immediately as frame decorations were set.
EXPECT_EQ("OnDisplaysChanged 2",
display_manager_observer1.GetAndClearObserverCalls());
// Remove the display and verify observer is notified.
display_manager->DestroyDisplay(display2);
display2 = nullptr;
EXPECT_EQ("OnDisplayRemoved 2",
display_manager_observer1.GetAndClearObserverCalls());
UserDisplayManagerTestApi(user_display_manager1).SetTestObserver(nullptr);
}
TEST_F(UserDisplayManagerTest, NegativeCoordinates) {
window_server_delegate_.set_num_displays_to_create(1);
const UserId kUserId1 = "2";
TestDisplayManagerObserver display_manager_observer1;
DisplayManager* display_manager = window_server_->display_manager();
WindowManagerWindowTreeFactorySetTestApi(
window_server_->window_manager_window_tree_factory_set())
.Add(kUserId1);
UserDisplayManager* user_display_manager1 =
display_manager->GetUserDisplayManager(kUserId1);
ASSERT_TRUE(user_display_manager1);
user_display_manager1->OnMouseCursorLocationChanged(gfx::Point(-10, -11));
base::subtle::Atomic32* cursor_location_memory = nullptr;
mojo::ScopedSharedBufferHandle handle =
user_display_manager1->GetCursorLocationMemory();
mojo::ScopedSharedBufferMapping cursor_location_mapping =
handle->Map(sizeof(base::subtle::Atomic32));
ASSERT_TRUE(cursor_location_mapping);
cursor_location_memory =
reinterpret_cast<base::subtle::Atomic32*>(cursor_location_mapping.get());
base::subtle::Atomic32 location =
base::subtle::NoBarrier_Load(cursor_location_memory);
EXPECT_EQ(gfx::Point(static_cast<int16_t>(location >> 16),
static_cast<int16_t>(location & 0xFFFF)),
gfx::Point(-10, -11));
}
} // namespace test
} // namespace ws
} // namespace mus