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 const DisplayModeX11 kDefaultDisplayMode(gfx::Size(1, 1), false, 60.0f, 20);
23 DisplaySnapshotX11* CreateOutput(RROutput output, RRCrtc crtc) {
24 DisplaySnapshotX11* snapshot = new DisplaySnapshotX11(
31 std::vector<const DisplayMode*>(1, &kDefaultDisplayMode),
41 class TestHelperDelegate : public NativeDisplayDelegateX11::HelperDelegate {
44 virtual ~TestHelperDelegate();
46 int num_calls_update_xrandr_config() const {
47 return num_calls_update_xrandr_config_;
50 int num_calls_notify_observers() const { return num_calls_notify_observers_; }
52 void set_cached_outputs(const std::vector<DisplaySnapshot*>& outputs) {
53 cached_outputs_ = outputs;
56 // NativeDisplayDelegateX11::HelperDelegate overrides:
57 virtual void UpdateXRandRConfiguration(const base::NativeEvent& event)
59 virtual const std::vector<DisplaySnapshot*>& GetCachedOutputs() const
61 virtual void NotifyDisplayObservers() OVERRIDE;
64 int num_calls_update_xrandr_config_;
65 int num_calls_notify_observers_;
67 std::vector<DisplaySnapshot*> cached_outputs_;
69 DISALLOW_COPY_AND_ASSIGN(TestHelperDelegate);
72 TestHelperDelegate::TestHelperDelegate()
73 : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {}
75 TestHelperDelegate::~TestHelperDelegate() {}
77 void TestHelperDelegate::UpdateXRandRConfiguration(
78 const base::NativeEvent& event) {
79 ++num_calls_update_xrandr_config_;
82 const std::vector<DisplaySnapshot*>& TestHelperDelegate::GetCachedOutputs()
84 return cached_outputs_;
87 void TestHelperDelegate::NotifyDisplayObservers() {
88 ++num_calls_notify_observers_;
91 ////////////////////////////////////////////////////////////////////////////////
92 // NativeDisplayEventDispatcherX11Test
94 class NativeDisplayEventDispatcherX11Test : public testing::Test {
96 NativeDisplayEventDispatcherX11Test();
97 virtual ~NativeDisplayEventDispatcherX11Test();
100 void DispatchScreenChangeEvent();
101 void DispatchOutputChangeEvent(RROutput output,
106 int xrandr_event_base_;
107 scoped_ptr<TestHelperDelegate> helper_delegate_;
108 scoped_ptr<NativeDisplayEventDispatcherX11> dispatcher_;
109 base::SimpleTestTickClock* test_tick_clock_; // Owned by |dispatcher_|.
112 DISALLOW_COPY_AND_ASSIGN(NativeDisplayEventDispatcherX11Test);
115 NativeDisplayEventDispatcherX11Test::NativeDisplayEventDispatcherX11Test()
116 : xrandr_event_base_(10),
117 helper_delegate_(new TestHelperDelegate()),
118 dispatcher_(new NativeDisplayEventDispatcherX11(helper_delegate_.get(),
119 xrandr_event_base_)),
120 test_tick_clock_(new base::SimpleTestTickClock) {
121 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1));
122 dispatcher_->SetTickClockForTest(
123 scoped_ptr<base::TickClock>(test_tick_clock_));
126 NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {}
128 void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() {
129 XRRScreenChangeNotifyEvent event = {0};
130 event.type = xrandr_event_base_ + RRScreenChangeNotify;
132 dispatcher_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
135 void NativeDisplayEventDispatcherX11Test::DispatchOutputChangeEvent(
140 XRROutputChangeNotifyEvent event = {0};
141 event.type = xrandr_event_base_ + RRNotify;
142 event.subtype = RRNotify_OutputChange;
143 event.output = output;
146 event.connection = connected ? RR_Connected : RR_Disconnected;
148 dispatcher_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
153 TEST_F(NativeDisplayEventDispatcherX11Test, OnScreenChangedEvent) {
154 DispatchScreenChangeEvent();
155 EXPECT_EQ(1, helper_delegate_->num_calls_update_xrandr_config());
156 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
159 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnFirstEvent) {
160 DispatchOutputChangeEvent(1, 10, 20, true);
161 EXPECT_EQ(0, helper_delegate_->num_calls_update_xrandr_config());
162 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
165 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationAfterSecondEvent) {
166 DispatchOutputChangeEvent(1, 10, 20, true);
168 // Simulate addition of the first output to the cached output list.
169 ScopedVector<DisplaySnapshot> outputs;
170 outputs.push_back(CreateOutput(1, 10));
171 helper_delegate_->set_cached_outputs(outputs.get());
173 DispatchOutputChangeEvent(2, 11, 20, true);
174 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
177 TEST_F(NativeDisplayEventDispatcherX11Test, AvoidNotificationOnDuplicateEvent) {
178 ScopedVector<DisplaySnapshot> outputs;
179 outputs.push_back(CreateOutput(1, 10));
180 helper_delegate_->set_cached_outputs(outputs.get());
182 // Very first event will not be ignored.
183 DispatchOutputChangeEvent(1, 10, 20, true);
184 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
186 DispatchOutputChangeEvent(1, 10, 20, true);
187 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
190 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDisconnect) {
191 ScopedVector<DisplaySnapshot> outputs;
192 outputs.push_back(CreateOutput(1, 10));
193 helper_delegate_->set_cached_outputs(outputs.get());
195 DispatchOutputChangeEvent(1, 10, 20, false);
196 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
199 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnModeChange) {
200 ScopedVector<DisplaySnapshot> outputs;
201 outputs.push_back(CreateOutput(1, 10));
202 helper_delegate_->set_cached_outputs(outputs.get());
204 DispatchOutputChangeEvent(1, 10, 21, true);
205 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
208 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnSecondOutput) {
209 ScopedVector<DisplaySnapshot> outputs;
210 outputs.push_back(CreateOutput(1, 10));
211 helper_delegate_->set_cached_outputs(outputs.get());
213 DispatchOutputChangeEvent(2, 11, 20, true);
214 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
217 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDifferentCrtc) {
218 ScopedVector<DisplaySnapshot> outputs;
219 outputs.push_back(CreateOutput(1, 10));
220 helper_delegate_->set_cached_outputs(outputs.get());
222 DispatchOutputChangeEvent(1, 11, 20, true);
223 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
226 TEST_F(NativeDisplayEventDispatcherX11Test,
227 CheckNotificationOnSecondOutputDisconnect) {
228 ScopedVector<DisplaySnapshot> outputs;
229 outputs.push_back(CreateOutput(1, 10));
230 outputs.push_back(CreateOutput(2, 11));
231 helper_delegate_->set_cached_outputs(outputs.get());
233 DispatchOutputChangeEvent(2, 11, 20, false);
234 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
237 TEST_F(NativeDisplayEventDispatcherX11Test,
238 AvoidDuplicateNotificationOnSecondOutputDisconnect) {
239 ScopedVector<DisplaySnapshot> outputs;
240 outputs.push_back(CreateOutput(1, 10));
241 outputs.push_back(CreateOutput(2, 11));
242 helper_delegate_->set_cached_outputs(outputs.get());
244 DispatchOutputChangeEvent(2, 11, 20, false);
245 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
247 // Simulate removal of second output from cached output list.
248 outputs.erase(outputs.begin() + 1);
249 helper_delegate_->set_cached_outputs(outputs.get());
251 DispatchOutputChangeEvent(2, 11, 20, false);
252 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
255 TEST_F(NativeDisplayEventDispatcherX11Test,
256 ForceUpdateAfterCacheExpiration) {
257 // +1 to compenstate a possible rounding error.
258 const int kHalfOfExpirationMs =
259 NativeDisplayEventDispatcherX11::kCachedOutputsExpirationMs / 2 + 1;
261 ScopedVector<DisplaySnapshot> outputs;
262 outputs.push_back(CreateOutput(1, 10));
263 outputs.push_back(CreateOutput(2, 11));
264 helper_delegate_->set_cached_outputs(outputs.get());
266 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers());
268 DispatchOutputChangeEvent(2, 11, 20, true);
269 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
271 // Duplicated event will be ignored.
272 DispatchOutputChangeEvent(2, 11, 20, true);
273 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
275 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(
276 kHalfOfExpirationMs));
278 // Duplicated event will still be ignored.
279 DispatchOutputChangeEvent(2, 11, 20, true);
280 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers());
282 // Duplicated event does notify after expiration timeout.
283 test_tick_clock_->Advance(
284 base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs));
285 DispatchOutputChangeEvent(2, 11, 20, true);
286 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
288 // Last update time has been updated, so next duplicated change event
290 DispatchOutputChangeEvent(2, 11, 20, true);
291 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());
293 // Another duplicated change event arrived within expiration time will
295 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(
296 kHalfOfExpirationMs));
297 DispatchOutputChangeEvent(2, 11, 20, true);
298 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers());