1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <X11/extensions/Xrandr.h>
10 #include "base/test/simple_test_tick_clock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/display/chromeos/x11/display_mode_x11.h"
13 #include "ui/display/chromeos/x11/display_snapshot_x11.h"
14 #include "ui/display/chromeos/x11/native_display_delegate_x11.h"
15 #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h"
21 DisplaySnapshotX11* CreateOutput(RROutput output, RRCrtc crtc) {
22 static const DisplayModeX11* kDefaultDisplayMode =
23 new DisplayModeX11(gfx::Size(1, 1), false, 60.0f, 20);
25 DisplaySnapshotX11* snapshot = new DisplaySnapshotX11(
32 std::vector<const DisplayMode*>(1, kDefaultDisplayMode),
42 class TestHelperDelegate : public NativeDisplayDelegateX11::HelperDelegate {
45 virtual ~TestHelperDelegate();
47 int num_calls_update_xrandr_config() const {
48 return num_calls_update_xrandr_config_;
51 int num_calls_notify_observers() const { return num_calls_notify_observers_; }
53 void set_cached_outputs(const std::vector<DisplaySnapshot*>& outputs) {
54 cached_outputs_ = outputs;
57 // NativeDisplayDelegateX11::HelperDelegate overrides:
58 virtual void UpdateXRandRConfiguration(const base::NativeEvent& event)
60 virtual const std::vector<DisplaySnapshot*>& GetCachedOutputs() const
62 virtual void NotifyDisplayObservers() OVERRIDE;
65 int num_calls_update_xrandr_config_;
66 int num_calls_notify_observers_;
68 std::vector<DisplaySnapshot*> cached_outputs_;
70 DISALLOW_COPY_AND_ASSIGN(TestHelperDelegate);
73 TestHelperDelegate::TestHelperDelegate()
74 : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {}
76 TestHelperDelegate::~TestHelperDelegate() {}
78 void TestHelperDelegate::UpdateXRandRConfiguration(
79 const base::NativeEvent& event) {
80 ++num_calls_update_xrandr_config_;
83 const std::vector<DisplaySnapshot*>& TestHelperDelegate::GetCachedOutputs()
85 return cached_outputs_;
88 void TestHelperDelegate::NotifyDisplayObservers() {
89 ++num_calls_notify_observers_;
92 ////////////////////////////////////////////////////////////////////////////////
93 // NativeDisplayEventDispatcherX11Test
95 class NativeDisplayEventDispatcherX11Test : public testing::Test {
97 NativeDisplayEventDispatcherX11Test();
98 virtual ~NativeDisplayEventDispatcherX11Test();
101 void DispatchScreenChangeEvent();
102 void DispatchOutputChangeEvent(RROutput output,
107 int xrandr_event_base_;
108 scoped_ptr<TestHelperDelegate> helper_delegate_;
109 scoped_ptr<NativeDisplayEventDispatcherX11> dispatcher_;
110 base::SimpleTestTickClock* test_tick_clock_; // Owned by |dispatcher_|.
113 DISALLOW_COPY_AND_ASSIGN(NativeDisplayEventDispatcherX11Test);
116 NativeDisplayEventDispatcherX11Test::NativeDisplayEventDispatcherX11Test()
117 : xrandr_event_base_(10),
118 helper_delegate_(new TestHelperDelegate()),
119 dispatcher_(new NativeDisplayEventDispatcherX11(helper_delegate_.get(),
120 xrandr_event_base_)),
121 test_tick_clock_(new base::SimpleTestTickClock) {
122 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1));
123 dispatcher_->SetTickClockForTest(
124 scoped_ptr<base::TickClock>(test_tick_clock_));
127 NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {}
129 void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() {
130 XRRScreenChangeNotifyEvent event = {0};
131 event.type = xrandr_event_base_ + RRScreenChangeNotify;
133 dispatcher_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
136 void NativeDisplayEventDispatcherX11Test::DispatchOutputChangeEvent(
141 XRROutputChangeNotifyEvent event = {0};
142 event.type = xrandr_event_base_ + RRNotify;
143 event.subtype = RRNotify_OutputChange;
144 event.output = output;
147 event.connection = connected ? RR_Connected : RR_Disconnected;
149 dispatcher_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
154 TEST_F(NativeDisplayEventDispatcherX11Test, OnScreenChangedEvent) {
155 DispatchScreenChangeEvent();
156 EXPECT_EQ(1, helper_delegate_->num_calls_update_xrandr_config());
157 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
160 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnFirstEvent) {
161 DispatchOutputChangeEvent(1, 10, 20, true);
162 EXPECT_EQ(0, helper_delegate_->num_calls_update_xrandr_config());
163 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
166 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationAfterSecondEvent) {
167 DispatchOutputChangeEvent(1, 10, 20, true);
169 // Simulate addition of the first output to the cached output list.
170 ScopedVector<DisplaySnapshot> outputs;
171 outputs.push_back(CreateOutput(1, 10));
172 helper_delegate_->set_cached_outputs(outputs.get());
174 DispatchOutputChangeEvent(2, 11, 20, true);
175 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
178 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDisconnect) {
179 ScopedVector<DisplaySnapshot> outputs;
180 outputs.push_back(CreateOutput(1, 10));
181 helper_delegate_->set_cached_outputs(outputs.get());
183 DispatchOutputChangeEvent(1, 10, 20, false);
184 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
187 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnModeChange) {
188 ScopedVector<DisplaySnapshot> outputs;
189 outputs.push_back(CreateOutput(1, 10));
190 helper_delegate_->set_cached_outputs(outputs.get());
192 DispatchOutputChangeEvent(1, 10, 21, true);
193 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
196 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnSecondOutput) {
197 ScopedVector<DisplaySnapshot> outputs;
198 outputs.push_back(CreateOutput(1, 10));
199 helper_delegate_->set_cached_outputs(outputs.get());
201 DispatchOutputChangeEvent(2, 11, 20, true);
202 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
205 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDifferentCrtc) {
206 ScopedVector<DisplaySnapshot> outputs;
207 outputs.push_back(CreateOutput(1, 10));
208 helper_delegate_->set_cached_outputs(outputs.get());
210 DispatchOutputChangeEvent(1, 11, 20, true);
211 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
214 TEST_F(NativeDisplayEventDispatcherX11Test,
215 CheckNotificationOnSecondOutputDisconnect) {
216 ScopedVector<DisplaySnapshot> outputs;
217 outputs.push_back(CreateOutput(1, 10));
218 outputs.push_back(CreateOutput(2, 11));
219 helper_delegate_->set_cached_outputs(outputs.get());
221 DispatchOutputChangeEvent(2, 11, 20, false);
222 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
225 TEST_F(NativeDisplayEventDispatcherX11Test,
226 AvoidDuplicateNotificationOnSecondOutputDisconnect) {
227 ScopedVector<DisplaySnapshot> outputs;
228 outputs.push_back(CreateOutput(1, 10));
229 outputs.push_back(CreateOutput(2, 11));
230 helper_delegate_->set_cached_outputs(outputs.get());
232 DispatchOutputChangeEvent(2, 11, 20, false);
233 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
235 // Simulate removal of second output from cached output list.
236 outputs.erase(outputs.begin() + 1);
237 helper_delegate_->set_cached_outputs(outputs.get());
239 DispatchOutputChangeEvent(2, 11, 20, false);
240 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
243 TEST_F(NativeDisplayEventDispatcherX11Test,
244 ForceUpdateAfterCacheExpiration) {
245 // +1 to compenstate a possible rounding error.
246 const int kHalfOfExpirationMs =
247 NativeDisplayEventDispatcherX11::kUseCacheAfterStartupMs / 2 + 1;
249 ScopedVector<DisplaySnapshot> outputs;
250 outputs.push_back(CreateOutput(1, 10));
251 outputs.push_back(CreateOutput(2, 11));
252 helper_delegate_->set_cached_outputs(outputs.get());
254 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
256 // Duplicated event will be ignored during the startup.
257 DispatchOutputChangeEvent(2, 11, 20, true);
258 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
260 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(
261 kHalfOfExpirationMs));
263 // Duplicated event will still be ignored.
264 DispatchOutputChangeEvent(2, 11, 20, true);
265 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
267 // The startup timeout has been elapsed. Duplicated event
268 // should not be ignored.
269 test_tick_clock_->Advance(
270 base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs));
271 DispatchOutputChangeEvent(2, 11, 20, true);
272 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
274 // Sending the same event immediately shoudldn't be ignored.
275 DispatchOutputChangeEvent(2, 11, 20, true);
276 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
278 // Advancing time further should not change the behavior.
279 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(
280 kHalfOfExpirationMs));
281 DispatchOutputChangeEvent(2, 11, 20, true);
282 EXPECT_EQ(3, helper_delegate_->num_calls_notify_observers());
284 test_tick_clock_->Advance(
285 base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs));
286 DispatchOutputChangeEvent(2, 11, 20, true);
287 EXPECT_EQ(4, helper_delegate_->num_calls_notify_observers());