Home | History | Annotate | Download | only in x11
      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