| OLD | NEW | 
 | (Empty) | 
|    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 <stdint.h> |  | 
|    6 #include <X11/extensions/Xrandr.h> |  | 
|    7  |  | 
|    8 #undef Bool |  | 
|    9 #undef None |  | 
|   10  |  | 
|   11 #include "base/macros.h" |  | 
|   12 #include "base/test/simple_test_tick_clock.h" |  | 
|   13 #include "testing/gtest/include/gtest/gtest.h" |  | 
|   14 #include "ui/display/chromeos/x11/display_mode_x11.h" |  | 
|   15 #include "ui/display/chromeos/x11/display_snapshot_x11.h" |  | 
|   16 #include "ui/display/chromeos/x11/native_display_delegate_x11.h" |  | 
|   17 #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h" |  | 
|   18  |  | 
|   19 namespace ui { |  | 
|   20  |  | 
|   21 namespace { |  | 
|   22  |  | 
|   23 DisplaySnapshotX11* CreateOutput(int64_t id, |  | 
|   24                                  DisplayConnectionType type, |  | 
|   25                                  RROutput output, |  | 
|   26                                  RRCrtc crtc) { |  | 
|   27   static const DisplayModeX11 kDefaultDisplayMode(gfx::Size(1, 1), |  | 
|   28                                                   false, |  | 
|   29                                                   60.0f, |  | 
|   30                                                   20); |  | 
|   31   std::vector<std::unique_ptr<const DisplayMode>> modes; |  | 
|   32   const DisplayMode* mode; |  | 
|   33  |  | 
|   34   modes.push_back(kDefaultDisplayMode.Clone()); |  | 
|   35   mode = modes.front().get(); |  | 
|   36  |  | 
|   37   DisplaySnapshotX11* snapshot = new DisplaySnapshotX11( |  | 
|   38       id, |  | 
|   39       gfx::Point(0, 0), |  | 
|   40       gfx::Size(0, 0), |  | 
|   41       type, |  | 
|   42       false, |  | 
|   43       false, |  | 
|   44       std::string(), |  | 
|   45       std::move(modes), |  | 
|   46       std::vector<uint8_t>(), |  | 
|   47       mode, |  | 
|   48       NULL, |  | 
|   49       output, |  | 
|   50       crtc, |  | 
|   51       0); |  | 
|   52  |  | 
|   53   return snapshot; |  | 
|   54 } |  | 
|   55  |  | 
|   56 DisplaySnapshotX11* CreateExternalOutput(RROutput output, RRCrtc crtc) { |  | 
|   57   return CreateOutput(static_cast<int64_t>(output), |  | 
|   58                       DISPLAY_CONNECTION_TYPE_UNKNOWN, |  | 
|   59                       output, |  | 
|   60                       crtc); |  | 
|   61 } |  | 
|   62  |  | 
|   63 DisplaySnapshotX11* CreateInternalOutput(RROutput output, RRCrtc crtc) { |  | 
|   64   return CreateOutput(0, |  | 
|   65                       DISPLAY_CONNECTION_TYPE_INTERNAL, |  | 
|   66                       output, |  | 
|   67                       crtc); |  | 
|   68 } |  | 
|   69  |  | 
|   70 class TestHelperDelegate : public NativeDisplayDelegateX11::HelperDelegate { |  | 
|   71  public: |  | 
|   72   TestHelperDelegate(); |  | 
|   73   ~TestHelperDelegate() override; |  | 
|   74  |  | 
|   75   int num_calls_update_xrandr_config() const { |  | 
|   76     return num_calls_update_xrandr_config_; |  | 
|   77   } |  | 
|   78  |  | 
|   79   int num_calls_notify_observers() const { return num_calls_notify_observers_; } |  | 
|   80  |  | 
|   81   void set_cached_outputs(const std::vector<DisplaySnapshot*>& outputs) { |  | 
|   82     cached_outputs_ = outputs; |  | 
|   83   } |  | 
|   84  |  | 
|   85   // NativeDisplayDelegateX11::HelperDelegate overrides: |  | 
|   86   void UpdateXRandRConfiguration(const base::NativeEvent& event) override; |  | 
|   87   const std::vector<DisplaySnapshot*>& GetCachedDisplays() const override; |  | 
|   88   void NotifyDisplayObservers() override; |  | 
|   89  |  | 
|   90  private: |  | 
|   91   int num_calls_update_xrandr_config_; |  | 
|   92   int num_calls_notify_observers_; |  | 
|   93  |  | 
|   94   std::vector<DisplaySnapshot*> cached_outputs_; |  | 
|   95  |  | 
|   96   DISALLOW_COPY_AND_ASSIGN(TestHelperDelegate); |  | 
|   97 }; |  | 
|   98  |  | 
|   99 TestHelperDelegate::TestHelperDelegate() |  | 
|  100     : num_calls_update_xrandr_config_(0), num_calls_notify_observers_(0) {} |  | 
|  101  |  | 
|  102 TestHelperDelegate::~TestHelperDelegate() {} |  | 
|  103  |  | 
|  104 void TestHelperDelegate::UpdateXRandRConfiguration( |  | 
|  105     const base::NativeEvent& event) { |  | 
|  106   ++num_calls_update_xrandr_config_; |  | 
|  107 } |  | 
|  108  |  | 
|  109 const std::vector<DisplaySnapshot*>& TestHelperDelegate::GetCachedDisplays() |  | 
|  110     const { |  | 
|  111   return cached_outputs_; |  | 
|  112 } |  | 
|  113  |  | 
|  114 void TestHelperDelegate::NotifyDisplayObservers() { |  | 
|  115   ++num_calls_notify_observers_; |  | 
|  116 } |  | 
|  117  |  | 
|  118 //////////////////////////////////////////////////////////////////////////////// |  | 
|  119 // NativeDisplayEventDispatcherX11Test |  | 
|  120  |  | 
|  121 class NativeDisplayEventDispatcherX11Test : public testing::Test { |  | 
|  122  public: |  | 
|  123   NativeDisplayEventDispatcherX11Test(); |  | 
|  124   ~NativeDisplayEventDispatcherX11Test() override; |  | 
|  125  |  | 
|  126  protected: |  | 
|  127   void DispatchScreenChangeEvent(); |  | 
|  128   void DispatchOutputChangeEvent(RROutput output, |  | 
|  129                                  RRCrtc crtc, |  | 
|  130                                  RRMode mode, |  | 
|  131                                  bool connected); |  | 
|  132  |  | 
|  133   int xrandr_event_base_; |  | 
|  134   std::unique_ptr<TestHelperDelegate> helper_delegate_; |  | 
|  135   std::unique_ptr<NativeDisplayEventDispatcherX11> dispatcher_; |  | 
|  136   base::SimpleTestTickClock* test_tick_clock_;  // Owned by |dispatcher_|. |  | 
|  137  |  | 
|  138  private: |  | 
|  139   DISALLOW_COPY_AND_ASSIGN(NativeDisplayEventDispatcherX11Test); |  | 
|  140 }; |  | 
|  141  |  | 
|  142 NativeDisplayEventDispatcherX11Test::NativeDisplayEventDispatcherX11Test() |  | 
|  143     : xrandr_event_base_(10), |  | 
|  144       helper_delegate_(new TestHelperDelegate()), |  | 
|  145       dispatcher_(new NativeDisplayEventDispatcherX11(helper_delegate_.get(), |  | 
|  146                                                       xrandr_event_base_)), |  | 
|  147       test_tick_clock_(new base::SimpleTestTickClock) { |  | 
|  148   test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1)); |  | 
|  149   dispatcher_->SetTickClockForTest( |  | 
|  150       std::unique_ptr<base::TickClock>(test_tick_clock_)); |  | 
|  151 } |  | 
|  152  |  | 
|  153 NativeDisplayEventDispatcherX11Test::~NativeDisplayEventDispatcherX11Test() {} |  | 
|  154  |  | 
|  155 void NativeDisplayEventDispatcherX11Test::DispatchScreenChangeEvent() { |  | 
|  156   XRRScreenChangeNotifyEvent event = {0}; |  | 
|  157   event.type = xrandr_event_base_ + RRScreenChangeNotify; |  | 
|  158  |  | 
|  159   dispatcher_->DispatchEvent(reinterpret_cast<const PlatformEvent>(&event)); |  | 
|  160 } |  | 
|  161  |  | 
|  162 void NativeDisplayEventDispatcherX11Test::DispatchOutputChangeEvent( |  | 
|  163     RROutput output, |  | 
|  164     RRCrtc crtc, |  | 
|  165     RRMode mode, |  | 
|  166     bool connected) { |  | 
|  167   XRROutputChangeNotifyEvent event = {0}; |  | 
|  168   event.type = xrandr_event_base_ + RRNotify; |  | 
|  169   event.subtype = RRNotify_OutputChange; |  | 
|  170   event.output = output; |  | 
|  171   event.crtc = crtc; |  | 
|  172   event.mode = mode; |  | 
|  173   event.connection = connected ? RR_Connected : RR_Disconnected; |  | 
|  174  |  | 
|  175   dispatcher_->DispatchEvent(reinterpret_cast<const PlatformEvent>(&event)); |  | 
|  176 } |  | 
|  177  |  | 
|  178 }  // namespace |  | 
|  179  |  | 
|  180 TEST_F(NativeDisplayEventDispatcherX11Test, OnScreenChangedEvent) { |  | 
|  181   DispatchScreenChangeEvent(); |  | 
|  182   EXPECT_EQ(1, helper_delegate_->num_calls_update_xrandr_config()); |  | 
|  183   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); |  | 
|  184 } |  | 
|  185  |  | 
|  186 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnFirstEvent) { |  | 
|  187   DispatchOutputChangeEvent(1, 10, 20, true); |  | 
|  188   EXPECT_EQ(0, helper_delegate_->num_calls_update_xrandr_config()); |  | 
|  189   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  190 } |  | 
|  191  |  | 
|  192 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationAfterSecondEvent) { |  | 
|  193   DispatchOutputChangeEvent(1, 10, 20, true); |  | 
|  194  |  | 
|  195   // Simulate addition of the first output to the cached output list. |  | 
|  196   ScopedVector<DisplaySnapshot> outputs; |  | 
|  197   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  198   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  199  |  | 
|  200   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  201   EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers()); |  | 
|  202 } |  | 
|  203  |  | 
|  204 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDisconnect) { |  | 
|  205   ScopedVector<DisplaySnapshot> outputs; |  | 
|  206   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  207   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  208  |  | 
|  209   DispatchOutputChangeEvent(1, 10, 20, false); |  | 
|  210   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  211 } |  | 
|  212  |  | 
|  213 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnModeChange) { |  | 
|  214   ScopedVector<DisplaySnapshot> outputs; |  | 
|  215   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  216   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  217  |  | 
|  218   DispatchOutputChangeEvent(1, 10, 21, true); |  | 
|  219   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  220 } |  | 
|  221  |  | 
|  222 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnSecondOutput) { |  | 
|  223   ScopedVector<DisplaySnapshot> outputs; |  | 
|  224   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  225   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  226  |  | 
|  227   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  228   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  229 } |  | 
|  230  |  | 
|  231 TEST_F(NativeDisplayEventDispatcherX11Test, CheckNotificationOnDifferentCrtc) { |  | 
|  232   ScopedVector<DisplaySnapshot> outputs; |  | 
|  233   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  234   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  235  |  | 
|  236   DispatchOutputChangeEvent(1, 11, 20, true); |  | 
|  237   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  238 } |  | 
|  239  |  | 
|  240 TEST_F(NativeDisplayEventDispatcherX11Test, |  | 
|  241        CheckNotificationOnSecondOutputDisconnect) { |  | 
|  242   ScopedVector<DisplaySnapshot> outputs; |  | 
|  243   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  244   outputs.push_back(CreateExternalOutput(2, 11)); |  | 
|  245   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  246  |  | 
|  247   DispatchOutputChangeEvent(2, 11, 20, false); |  | 
|  248   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  249 } |  | 
|  250  |  | 
|  251 TEST_F(NativeDisplayEventDispatcherX11Test, |  | 
|  252        AvoidDuplicateNotificationOnSecondOutputDisconnect) { |  | 
|  253   ScopedVector<DisplaySnapshot> outputs; |  | 
|  254   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  255   outputs.push_back(CreateExternalOutput(2, 11)); |  | 
|  256   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  257  |  | 
|  258   DispatchOutputChangeEvent(2, 11, 20, false); |  | 
|  259   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  260  |  | 
|  261   // Simulate removal of second output from cached output list. |  | 
|  262   outputs.erase(outputs.begin() + 1); |  | 
|  263   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  264  |  | 
|  265   DispatchOutputChangeEvent(2, 11, 20, false); |  | 
|  266   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  267 } |  | 
|  268  |  | 
|  269 TEST_F(NativeDisplayEventDispatcherX11Test, |  | 
|  270        ForceUpdateAfterCacheExpiration) { |  | 
|  271   // +1 to compenstate a possible rounding error. |  | 
|  272   const int kHalfOfExpirationMs = |  | 
|  273       NativeDisplayEventDispatcherX11::kUseCacheAfterStartupMs / 2 + 1; |  | 
|  274  |  | 
|  275   ScopedVector<DisplaySnapshot> outputs; |  | 
|  276   outputs.push_back(CreateExternalOutput(1, 10)); |  | 
|  277   outputs.push_back(CreateExternalOutput(2, 11)); |  | 
|  278   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  279  |  | 
|  280   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); |  | 
|  281  |  | 
|  282   // Duplicated event will be ignored during the startup. |  | 
|  283   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  284   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); |  | 
|  285  |  | 
|  286   test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds( |  | 
|  287       kHalfOfExpirationMs)); |  | 
|  288  |  | 
|  289   // Duplicated event will still be ignored. |  | 
|  290   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  291   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); |  | 
|  292  |  | 
|  293   // The startup timeout has been elapsed. Duplicated event |  | 
|  294   // should not be ignored. |  | 
|  295   test_tick_clock_->Advance( |  | 
|  296       base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs)); |  | 
|  297   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  298   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  299  |  | 
|  300   // Sending the same event immediately shoudldn't be ignored. |  | 
|  301   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  302   EXPECT_EQ(2, helper_delegate_->num_calls_notify_observers()); |  | 
|  303  |  | 
|  304   // Advancing time further should not change the behavior. |  | 
|  305   test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds( |  | 
|  306       kHalfOfExpirationMs)); |  | 
|  307   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  308   EXPECT_EQ(3, helper_delegate_->num_calls_notify_observers()); |  | 
|  309  |  | 
|  310   test_tick_clock_->Advance( |  | 
|  311       base::TimeDelta::FromMilliseconds(kHalfOfExpirationMs)); |  | 
|  312   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  313   EXPECT_EQ(4, helper_delegate_->num_calls_notify_observers()); |  | 
|  314 } |  | 
|  315  |  | 
|  316 TEST_F(NativeDisplayEventDispatcherX11Test, |  | 
|  317        UpdateMissingExternalDisplayId) { |  | 
|  318   ScopedVector<DisplaySnapshot> outputs; |  | 
|  319   outputs.push_back(CreateInternalOutput(1, 10)); |  | 
|  320   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  321  |  | 
|  322   ASSERT_EQ(0, helper_delegate_->num_calls_notify_observers()); |  | 
|  323  |  | 
|  324   // Internal display's ID can be zero and not updated. |  | 
|  325   DispatchOutputChangeEvent(1, 10, 20, true); |  | 
|  326   EXPECT_EQ(0, helper_delegate_->num_calls_notify_observers()); |  | 
|  327  |  | 
|  328   outputs.clear(); |  | 
|  329   outputs.push_back(CreateOutput(0, DISPLAY_CONNECTION_TYPE_UNKNOWN, 2, 11)); |  | 
|  330   helper_delegate_->set_cached_outputs(outputs.get()); |  | 
|  331  |  | 
|  332   // External display should be updated if the id is zero. |  | 
|  333   DispatchOutputChangeEvent(2, 11, 20, true); |  | 
|  334   EXPECT_EQ(1, helper_delegate_->num_calls_notify_observers()); |  | 
|  335 } |  | 
|  336  |  | 
|  337 }  // namespace ui |  | 
| OLD | NEW |