blob: ad4c60e07bf72fe3f6fc4985c7b30597f477c994 [file] [log] [blame]
// Copyright (c) 2013 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/views/widget/desktop_aura/desktop_screen_x11.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/hit_test.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/x/x11_display_manager.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/display.h"
#include "ui/display/display_observer.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
namespace {
// Class which allows for the designation of non-client component targets of
// hit tests.
class TestDesktopNativeWidgetAura : public views::DesktopNativeWidgetAura {
public:
explicit TestDesktopNativeWidgetAura(
views::internal::NativeWidgetDelegate* delegate)
: views::DesktopNativeWidgetAura(delegate) {}
~TestDesktopNativeWidgetAura() override = default;
void set_window_component(int window_component) {
window_component_ = window_component;
}
// DesktopNativeWidgetAura:
int GetNonClientComponent(const gfx::Point& point) const override {
return window_component_;
}
private:
int window_component_;
DISALLOW_COPY_AND_ASSIGN(TestDesktopNativeWidgetAura);
};
} // namespace
namespace views {
constexpr int64_t kFirstDisplay = 5321829;
constexpr int64_t kSecondDisplay = 928310;
class DesktopScreenX11Test : public views::ViewsTestBase,
public display::DisplayObserver {
public:
DesktopScreenX11Test() = default;
~DesktopScreenX11Test() override = default;
// Overridden from testing::Test:
void SetUp() override {
ViewsTestBase::SetUp();
// TODO(crbug.com/1096425): Once non-Ozone X11 is deprecated, re-work this.
if (features::IsUsingOzonePlatform())
GTEST_SKIP();
// Initialize the world to the single monitor case.
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
screen_ = std::make_unique<DesktopScreenX11>();
UpdateDisplayListForTest(displays);
screen_->AddObserver(this);
}
void TearDown() override {
screen_.reset();
ViewsTestBase::TearDown();
}
protected:
std::vector<display::Display> changed_display_;
std::vector<display::Display> added_display_;
std::vector<display::Display> removed_display_;
DesktopScreenX11* screen() { return screen_.get(); }
void UpdateDisplayListForTest(std::vector<display::Display> displays) {
ui::XDisplayManager* manager = screen_->x11_display_manager_.get();
std::vector<display::Display> old_displays = std::move(manager->displays_);
manager->SetDisplayList(std::move(displays));
manager->change_notifier_.NotifyDisplaysChanged(old_displays,
manager->displays_);
}
void ResetDisplayChanges() {
changed_display_.clear();
added_display_.clear();
removed_display_.clear();
}
Widget* BuildTopLevelDesktopWidget(const gfx::Rect& bounds,
bool use_test_native_widget) {
Widget* toplevel = new Widget;
Widget::InitParams toplevel_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
if (use_test_native_widget) {
toplevel_params.native_widget = new TestDesktopNativeWidgetAura(toplevel);
} else {
toplevel_params.native_widget =
new views::DesktopNativeWidgetAura(toplevel);
}
toplevel_params.bounds = bounds;
toplevel_params.remove_standard_frame = true;
toplevel->Init(std::move(toplevel_params));
return toplevel;
}
private:
// Overridden from display::DisplayObserver:
void OnDisplayAdded(const display::Display& new_display) override {
added_display_.push_back(new_display);
}
void OnDisplayRemoved(const display::Display& old_display) override {
removed_display_.push_back(old_display);
}
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) override {
changed_display_.push_back(display);
}
std::unique_ptr<DesktopScreenX11> screen_;
DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11Test);
};
TEST_F(DesktopScreenX11Test, BoundsChangeSingleMonitor) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(0u, added_display_.size());
EXPECT_EQ(0u, removed_display_.size());
}
TEST_F(DesktopScreenX11Test, AddMonitorToTheRight) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(0u, changed_display_.size());
EXPECT_EQ(1u, added_display_.size());
EXPECT_EQ(0u, removed_display_.size());
}
TEST_F(DesktopScreenX11Test, AddMonitorToTheLeft) {
std::vector<display::Display> displays;
displays.emplace_back(kSecondDisplay, gfx::Rect(0, 0, 1024, 768));
displays.emplace_back(kFirstDisplay, gfx::Rect(1024, 0, 640, 480));
UpdateDisplayListForTest(displays);
EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(1u, added_display_.size());
EXPECT_EQ(0u, removed_display_.size());
}
TEST_F(DesktopScreenX11Test, RemoveMonitorOnRight) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
ResetDisplayChanges();
displays.clear();
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
UpdateDisplayListForTest(displays);
EXPECT_EQ(0u, changed_display_.size());
EXPECT_EQ(0u, added_display_.size());
EXPECT_EQ(1u, removed_display_.size());
}
TEST_F(DesktopScreenX11Test, RemoveMonitorOnLeft) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
ResetDisplayChanges();
displays.clear();
displays.emplace_back(kSecondDisplay, gfx::Rect(0, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(0u, added_display_.size());
EXPECT_EQ(1u, removed_display_.size());
}
TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(kFirstDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(630, 10)).id());
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(650, 10)).id());
EXPECT_EQ(kFirstDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(10, 10)).id());
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(10000, 10000)).id());
EXPECT_EQ(kFirstDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(639, -10)).id());
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(641, -20)).id());
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(600, 760)).id());
EXPECT_EQ(kFirstDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(-1000, 760)).id());
}
TEST_F(DesktopScreenX11Test, GetDisplayMatchingBasic) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayMatching(gfx::Rect(700, 20, 100, 100)).id());
}
TEST_F(DesktopScreenX11Test, GetDisplayMatchingOverlap) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayMatching(gfx::Rect(630, 20, 100, 100)).id());
}
TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(640, 0, 1024, 768));
displays.emplace_back(kSecondDisplay, gfx::Rect(0, 0, 640, 480));
UpdateDisplayListForTest(displays);
// The first display in the list is always the primary, even if other
// displays are to the left in screen layout.
EXPECT_EQ(kFirstDisplay, screen()->GetPrimaryDisplay().id());
}
TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) {
// Set up a two monitor situation.
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
Widget* window_one =
BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10), false);
Widget* window_two =
BuildTopLevelDesktopWidget(gfx::Rect(650, 50, 10, 10), false);
EXPECT_EQ(
kFirstDisplay,
screen()->GetDisplayNearestWindow(window_one->GetNativeWindow()).id());
EXPECT_EQ(
kSecondDisplay,
screen()->GetDisplayNearestWindow(window_two->GetNativeWindow()).id());
window_one->CloseNow();
window_two->CloseNow();
}
// Test that rotating the displays notifies the DisplayObservers.
TEST_F(DesktopScreenX11Test, RotationChange) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
ResetDisplayChanges();
displays[0].set_rotation(display::Display::ROTATE_90);
UpdateDisplayListForTest(displays);
EXPECT_EQ(1u, changed_display_.size());
displays[1].set_rotation(display::Display::ROTATE_90);
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[0].set_rotation(display::Display::ROTATE_270);
UpdateDisplayListForTest(displays);
EXPECT_EQ(3u, changed_display_.size());
displays[0].set_rotation(display::Display::ROTATE_270);
UpdateDisplayListForTest(displays);
EXPECT_EQ(3u, changed_display_.size());
displays[0].set_rotation(display::Display::ROTATE_0);
displays[1].set_rotation(display::Display::ROTATE_0);
UpdateDisplayListForTest(displays);
EXPECT_EQ(5u, changed_display_.size());
}
// Test that changing the displays workarea notifies the DisplayObservers.
TEST_F(DesktopScreenX11Test, WorkareaChange) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
ResetDisplayChanges();
displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
UpdateDisplayListForTest(displays);
EXPECT_EQ(1u, changed_display_.size());
displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[0].set_work_area(gfx::Rect(0, 0, 640, 480));
displays[1].set_work_area(gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
EXPECT_EQ(4u, changed_display_.size());
}
// Test that changing the device scale factor notifies the DisplayObservers.
TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) {
std::vector<display::Display> displays;
displays.emplace_back(kFirstDisplay, gfx::Rect(0, 0, 640, 480));
displays.emplace_back(kSecondDisplay, gfx::Rect(640, 0, 1024, 768));
UpdateDisplayListForTest(displays);
ResetDisplayChanges();
displays[0].set_device_scale_factor(2.5f);
UpdateDisplayListForTest(displays);
EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(2.5f, gfx::GetFontRenderParamsDeviceScaleFactor());
displays[1].set_device_scale_factor(2.5f);
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[0].set_device_scale_factor(2.5f);
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[1].set_device_scale_factor(2.5f);
UpdateDisplayListForTest(displays);
EXPECT_EQ(2u, changed_display_.size());
displays[0].set_device_scale_factor(1.f);
displays[1].set_device_scale_factor(1.f);
UpdateDisplayListForTest(displays);
EXPECT_EQ(4u, changed_display_.size());
EXPECT_EQ(1.f, gfx::GetFontRenderParamsDeviceScaleFactor());
}
} // namespace views