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(
30 DISPLAY_CONNECTION_TYPE_UNKNOWN
,
34 std::vector
<const DisplayMode
*>(1, kDefaultDisplayMode
),
44 class TestHelperDelegate
: public NativeDisplayDelegateX11::HelperDelegate
{
47 virtual ~TestHelperDelegate();
49 int num_calls_update_xrandr_config() const {
50 return num_calls_update_xrandr_config_
;
53 int num_calls_notify_observers() const { return num_calls_notify_observers_
; }
55 void set_cached_outputs(const std::vector
<DisplaySnapshot
*>& outputs
) {
56 cached_outputs_
= outputs
;
59 // NativeDisplayDelegateX11::HelperDelegate overrides:
60 virtual void UpdateXRandRConfiguration(const base::NativeEvent
& event
)
62 virtual const std::vector
<DisplaySnapshot
*>& GetCachedDisplays() const
64 virtual void NotifyDisplayObservers() OVERRIDE
;
67 int num_calls_update_xrandr_config_
;
68 int num_calls_notify_observers_
;
70 std::vector
<DisplaySnapshot
*> cached_outputs_
;
72 DISALLOW_COPY_AND_ASSIGN(TestHelperDelegate
);
75 TestHelperDelegate::TestHelperDelegate()
76 : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {}
78 TestHelperDelegate::~TestHelperDelegate() {}
80 void TestHelperDelegate::UpdateXRandRConfiguration(
81 const base::NativeEvent
& event
) {
82 ++num_calls_update_xrandr_config_
;
85 const std::vector
<DisplaySnapshot
*>& TestHelperDelegate::GetCachedDisplays()
87 return cached_outputs_
;
90 void TestHelperDelegate::NotifyDisplayObservers() {
91 ++num_calls_notify_observers_
;
94 ////////////////////////////////////////////////////////////////////////////////
95 // NativeDisplayEventDispatcherX11Test
97 class NativeDisplayEventDispatcherX11Test
: public testing::Test
{
99 NativeDisplayEventDispatcherX11Test();
100 virtual ~NativeDisplayEventDispatcherX11Test();
103 void DispatchScreenChangeEvent();
104 void DispatchOutputChangeEvent(RROutput output
,
109 int xrandr_event_base_
;
110 scoped_ptr
<TestHelperDelegate
> helper_delegate_
;
111 scoped_ptr
<NativeDisplayEventDispatcherX11
> dispatcher_
;
112 base::SimpleTestTickClock
* test_tick_clock_
; // Owned by |dispatcher_|.
115 DISALLOW_COPY_AND_ASSIGN(NativeDisplayEventDispatcherX11Test
);
118 NativeDisplayEventDispatcherX11Test::NativeDisplayEventDispatcherX11Test()
119 : xrandr_event_base_(10),
120 helper_delegate_(new TestHelperDelegate()),
121 dispatcher_(new NativeDisplayEventDispatcherX11(helper_delegate_
.get(),
122 xrandr_event_base_
)),
123 test_tick_clock_(new base::SimpleTestTickClock
) {
124 test_tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(1));
125 dispatcher_
->SetTickClockForTest(
126 scoped_ptr
<base::TickClock
>(test_tick_clock_
));
129 NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {}
131 void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() {
132 XRRScreenChangeNotifyEvent event
= {0};
133 event
.type
= xrandr_event_base_
+ RRScreenChangeNotify
;
135 dispatcher_
->DispatchEvent(reinterpret_cast<const PlatformEvent
>(&event
));
138 void NativeDisplayEventDispatcherX11Test::DispatchOutputChangeEvent(
143 XRROutputChangeNotifyEvent event
= {0};
144 event
.type
= xrandr_event_base_
+ RRNotify
;
145 event
.subtype
= RRNotify_OutputChange
;
146 event
.output
= output
;
149 event
.connection
= connected
? RR_Connected
: RR_Disconnected
;
151 dispatcher_
->DispatchEvent(reinterpret_cast<const PlatformEvent
>(&event
));
156 TEST_F(NativeDisplayEventDispatcherX11Test
, OnScreenChangedEvent
) {
157 DispatchScreenChangeEvent();
158 EXPECT_EQ(1, helper_delegate_
->num_calls_update_xrandr_config());
159 EXPECT_EQ(0, helper_delegate_
->num_calls_notify_observers());
162 TEST_F(NativeDisplayEventDispatcherX11Test
, CheckNotificationOnFirstEvent
) {
163 DispatchOutputChangeEvent(1, 10, 20, true);
164 EXPECT_EQ(0, helper_delegate_
->num_calls_update_xrandr_config());
165 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
168 TEST_F(NativeDisplayEventDispatcherX11Test
, CheckNotificationAfterSecondEvent
) {
169 DispatchOutputChangeEvent(1, 10, 20, true);
171 // Simulate addition of the first output to the cached output list.
172 ScopedVector
<DisplaySnapshot
> outputs
;
173 outputs
.push_back(CreateOutput(1, 10));
174 helper_delegate_
->set_cached_outputs(outputs
.get());
176 DispatchOutputChangeEvent(2, 11, 20, true);
177 EXPECT_EQ(2, helper_delegate_
->num_calls_notify_observers());
180 TEST_F(NativeDisplayEventDispatcherX11Test
, CheckNotificationOnDisconnect
) {
181 ScopedVector
<DisplaySnapshot
> outputs
;
182 outputs
.push_back(CreateOutput(1, 10));
183 helper_delegate_
->set_cached_outputs(outputs
.get());
185 DispatchOutputChangeEvent(1, 10, 20, false);
186 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
189 TEST_F(NativeDisplayEventDispatcherX11Test
, CheckNotificationOnModeChange
) {
190 ScopedVector
<DisplaySnapshot
> outputs
;
191 outputs
.push_back(CreateOutput(1, 10));
192 helper_delegate_
->set_cached_outputs(outputs
.get());
194 DispatchOutputChangeEvent(1, 10, 21, true);
195 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
198 TEST_F(NativeDisplayEventDispatcherX11Test
, CheckNotificationOnSecondOutput
) {
199 ScopedVector
<DisplaySnapshot
> outputs
;
200 outputs
.push_back(CreateOutput(1, 10));
201 helper_delegate_
->set_cached_outputs(outputs
.get());
203 DispatchOutputChangeEvent(2, 11, 20, true);
204 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
207 TEST_F(NativeDisplayEventDispatcherX11Test
, CheckNotificationOnDifferentCrtc
) {
208 ScopedVector
<DisplaySnapshot
> outputs
;
209 outputs
.push_back(CreateOutput(1, 10));
210 helper_delegate_
->set_cached_outputs(outputs
.get());
212 DispatchOutputChangeEvent(1, 11, 20, true);
213 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
216 TEST_F(NativeDisplayEventDispatcherX11Test
,
217 CheckNotificationOnSecondOutputDisconnect
) {
218 ScopedVector
<DisplaySnapshot
> outputs
;
219 outputs
.push_back(CreateOutput(1, 10));
220 outputs
.push_back(CreateOutput(2, 11));
221 helper_delegate_
->set_cached_outputs(outputs
.get());
223 DispatchOutputChangeEvent(2, 11, 20, false);
224 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
227 TEST_F(NativeDisplayEventDispatcherX11Test
,
228 AvoidDuplicateNotificationOnSecondOutputDisconnect
) {
229 ScopedVector
<DisplaySnapshot
> outputs
;
230 outputs
.push_back(CreateOutput(1, 10));
231 outputs
.push_back(CreateOutput(2, 11));
232 helper_delegate_
->set_cached_outputs(outputs
.get());
234 DispatchOutputChangeEvent(2, 11, 20, false);
235 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
237 // Simulate removal of second output from cached output list.
238 outputs
.erase(outputs
.begin() + 1);
239 helper_delegate_
->set_cached_outputs(outputs
.get());
241 DispatchOutputChangeEvent(2, 11, 20, false);
242 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
245 TEST_F(NativeDisplayEventDispatcherX11Test
,
246 ForceUpdateAfterCacheExpiration
) {
247 // +1 to compenstate a possible rounding error.
248 const int kHalfOfExpirationMs
=
249 NativeDisplayEventDispatcherX11::kUseCacheAfterStartupMs
/ 2 + 1;
251 ScopedVector
<DisplaySnapshot
> outputs
;
252 outputs
.push_back(CreateOutput(1, 10));
253 outputs
.push_back(CreateOutput(2, 11));
254 helper_delegate_
->set_cached_outputs(outputs
.get());
256 EXPECT_EQ(0, helper_delegate_
->num_calls_notify_observers());
258 // Duplicated event will be ignored during the startup.
259 DispatchOutputChangeEvent(2, 11, 20, true);
260 EXPECT_EQ(0, helper_delegate_
->num_calls_notify_observers());
262 test_tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(
263 kHalfOfExpirationMs
));
265 // Duplicated event will still be ignored.
266 DispatchOutputChangeEvent(2, 11, 20, true);
267 EXPECT_EQ(0, helper_delegate_
->num_calls_notify_observers());
269 // The startup timeout has been elapsed. Duplicated event
270 // should not be ignored.
271 test_tick_clock_
->Advance(
272 base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs
));
273 DispatchOutputChangeEvent(2, 11, 20, true);
274 EXPECT_EQ(1, helper_delegate_
->num_calls_notify_observers());
276 // Sending the same event immediately shoudldn't be ignored.
277 DispatchOutputChangeEvent(2, 11, 20, true);
278 EXPECT_EQ(2, helper_delegate_
->num_calls_notify_observers());
280 // Advancing time further should not change the behavior.
281 test_tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(
282 kHalfOfExpirationMs
));
283 DispatchOutputChangeEvent(2, 11, 20, true);
284 EXPECT_EQ(3, helper_delegate_
->num_calls_notify_observers());
286 test_tick_clock_
->Advance(
287 base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs
));
288 DispatchOutputChangeEvent(2, 11, 20, true);
289 EXPECT_EQ(4, helper_delegate_
->num_calls_notify_observers());