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. 4 5#include <X11/extensions/Xrandr.h> 6 7#undef Bool 8#undef None 9 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" 16 17namespace ui { 18 19namespace { 20 21DisplaySnapshotX11* CreateOutput(RROutput output, RRCrtc crtc) { 22 static const DisplayModeX11* kDefaultDisplayMode = 23 new DisplayModeX11(gfx::Size(1, 1), false, 60.0f, 20); 24 25 DisplaySnapshotX11* snapshot = new DisplaySnapshotX11( 26 0, 27 false, 28 gfx::Point(0, 0), 29 gfx::Size(0, 0), 30 DISPLAY_CONNECTION_TYPE_UNKNOWN, 31 false, 32 false, 33 std::string(), 34 std::vector<const DisplayMode*>(1, kDefaultDisplayMode), 35 kDefaultDisplayMode, 36 NULL, 37 output, 38 crtc, 39 0); 40 41 return snapshot; 42} 43 44class TestHelperDelegate : public NativeDisplayDelegateX11::HelperDelegate { 45 public: 46 TestHelperDelegate(); 47 virtual ~TestHelperDelegate(); 48 49 int num_calls_update_xrandr_config() const { 50 return num_calls_update_xrandr_config_; 51 } 52 53 int num_calls_notify_observers() const { return num_calls_notify_observers_; } 54 55 void set_cached_outputs(const std::vector<DisplaySnapshot*>& outputs) { 56 cached_outputs_ = outputs; 57 } 58 59 // NativeDisplayDelegateX11::HelperDelegate overrides: 60 virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) 61 OVERRIDE; 62 virtual const std::vector<DisplaySnapshot*>& GetCachedDisplays() const 63 OVERRIDE; 64 virtual void NotifyDisplayObservers() OVERRIDE; 65 66 private: 67 int num_calls_update_xrandr_config_; 68 int num_calls_notify_observers_; 69 70 std::vector<DisplaySnapshot*> cached_outputs_; 71 72 DISALLOW_COPY_AND_ASSIGN(TestHelperDelegate); 73}; 74 75TestHelperDelegate::TestHelperDelegate() 76 : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {} 77 78TestHelperDelegate::~TestHelperDelegate() {} 79 80void TestHelperDelegate::UpdateXRandRConfiguration( 81 const base::NativeEvent& event) { 82 ++num_calls_update_xrandr_config_; 83} 84 85const std::vector<DisplaySnapshot*>& TestHelperDelegate::GetCachedDisplays() 86 const { 87 return cached_outputs_; 88} 89 90void TestHelperDelegate::NotifyDisplayObservers() { 91 ++num_calls_notify_observers_; 92} 93 94//////////////////////////////////////////////////////////////////////////////// 95// NativeDisplayEventDispatcherX11Test 96 97class NativeDisplayEventDispatcherX11Test : public testing::Test { 98 public: 99 NativeDisplayEventDispatcherX11Test(); 100 virtual ~NativeDisplayEventDispatcherX11Test(); 101 102 protected: 103 void DispatchScreenChangeEvent(); 104 void DispatchOutputChangeEvent(RROutput output, 105 RRCrtc crtc, 106 RRMode mode, 107 bool connected); 108 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_|. 113 114 private: 115 DISALLOW_COPY_AND_ASSIGN(NativeDisplayEventDispatcherX11Test); 116}; 117 118NativeDisplayEventDispatcherX11Test::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_)); 127} 128 129NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {} 130 131void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() { 132 XRRScreenChangeNotifyEvent event = {0}; 133 event.type = xrandr_event_base_ + RRScreenChangeNotify; 134 135 dispatcher_->DispatchEvent(reinterpret_cast<const PlatformEvent>(&event)); 136} 137 138void NativeDisplayEventDispatcherX11Test::DispatchOutputChangeEvent( 139 RROutput output, 140 RRCrtc crtc, 141 RRMode mode, 142 bool connected) { 143 XRROutputChangeNotifyEvent event = {0}; 144 event.type = xrandr_event_base_ + RRNotify; 145 event.subtype = RRNotify_OutputChange; 146 event.output = output; 147 event.crtc = crtc; 148 event.mode = mode; 149 event.connection = connected ? RR_Connected : RR_Disconnected; 150 151 dispatcher_->DispatchEvent(reinterpret_cast<const PlatformEvent>(&event)); 152} 153 154} // namespace 155 156TEST_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()); 160} 161 162TEST_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()); 166} 167 168TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationAfterSecondEvent) { 169 DispatchOutputChangeEvent(1, 10, 20, true); 170 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()); 175 176 DispatchOutputChangeEvent(2, 11, 20, true); 177 EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers()); 178} 179 180TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDisconnect) { 181 ScopedVector<DisplaySnapshot> outputs; 182 outputs.push_back(CreateOutput(1, 10)); 183 helper_delegate_->set_cached_outputs(outputs.get()); 184 185 DispatchOutputChangeEvent(1, 10, 20, false); 186 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 187} 188 189TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnModeChange) { 190 ScopedVector<DisplaySnapshot> outputs; 191 outputs.push_back(CreateOutput(1, 10)); 192 helper_delegate_->set_cached_outputs(outputs.get()); 193 194 DispatchOutputChangeEvent(1, 10, 21, true); 195 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 196} 197 198TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnSecondOutput) { 199 ScopedVector<DisplaySnapshot> outputs; 200 outputs.push_back(CreateOutput(1, 10)); 201 helper_delegate_->set_cached_outputs(outputs.get()); 202 203 DispatchOutputChangeEvent(2, 11, 20, true); 204 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 205} 206 207TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDifferentCrtc) { 208 ScopedVector<DisplaySnapshot> outputs; 209 outputs.push_back(CreateOutput(1, 10)); 210 helper_delegate_->set_cached_outputs(outputs.get()); 211 212 DispatchOutputChangeEvent(1, 11, 20, true); 213 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 214} 215 216TEST_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()); 222 223 DispatchOutputChangeEvent(2, 11, 20, false); 224 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 225} 226 227TEST_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()); 233 234 DispatchOutputChangeEvent(2, 11, 20, false); 235 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 236 237 // Simulate removal of second output from cached output list. 238 outputs.erase(outputs.begin() + 1); 239 helper_delegate_->set_cached_outputs(outputs.get()); 240 241 DispatchOutputChangeEvent(2, 11, 20, false); 242 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 243} 244 245TEST_F(NativeDisplayEventDispatcherX11Test, 246 ForceUpdateAfterCacheExpiration) { 247 // +1 to compenstate a possible rounding error. 248 const int kHalfOfExpirationMs = 249 NativeDisplayEventDispatcherX11::kUseCacheAfterStartupMs / 2 + 1; 250 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()); 255 256 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); 257 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()); 261 262 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds( 263 kHalfOfExpirationMs)); 264 265 // Duplicated event will still be ignored. 266 DispatchOutputChangeEvent(2, 11, 20, true); 267 EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); 268 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()); 275 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()); 279 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()); 285 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()); 290} 291 292} // namespace ui 293