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 17 namespace ui { 18 19 namespace { 20 21 DisplaySnapshotX11* 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 44 class 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 75 TestHelperDelegate::TestHelperDelegate() 76 : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {} 77 78 TestHelperDelegate::~TestHelperDelegate() {} 79 80 void TestHelperDelegate::UpdateXRandRConfiguration( 81 const base::NativeEvent& event) { 82 ++num_calls_update_xrandr_config_; 83 } 84 85 const std::vector<DisplaySnapshot*>& TestHelperDelegate::GetCachedDisplays() 86 const { 87 return cached_outputs_; 88 } 89 90 void TestHelperDelegate::NotifyDisplayObservers() { 91 ++num_calls_notify_observers_; 92 } 93 94 //////////////////////////////////////////////////////////////////////////////// 95 // NativeDisplayEventDispatcherX11Test 96 97 class 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 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_)); 127 } 128 129 NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {} 130 131 void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() { 132 XRRScreenChangeNotifyEvent event = {0}; 133 event.type = xrandr_event_base_ + RRScreenChangeNotify; 134 135 dispatcher_->DispatchEvent(reinterpret_cast<const PlatformEvent>(&event)); 136 } 137 138 void 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 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()); 160 } 161 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()); 166 } 167 168 TEST_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 180 TEST_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 189 TEST_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 198 TEST_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 207 TEST_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 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()); 222 223 DispatchOutputChangeEvent(2, 11, 20, false); 224 EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); 225 } 226 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()); 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 245 TEST_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