Home | History | Annotate | Download | only in desktop_aura
      1 // Copyright (c) 2013 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 "ui/views/widget/desktop_aura/desktop_screen_x11.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 #include "ui/aura/client/aura_constants.h"
     10 #include "ui/aura/window.h"
     11 #include "ui/aura/window_event_dispatcher.h"
     12 #include "ui/base/hit_test.h"
     13 #include "ui/base/x/x11_util.h"
     14 #include "ui/events/test/event_generator.h"
     15 #include "ui/gfx/display_observer.h"
     16 #include "ui/gfx/x/x11_types.h"
     17 #include "ui/views/test/views_test_base.h"
     18 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
     19 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
     20 
     21 namespace {
     22 
     23 // Class which allows for the designation of non-client component targets of
     24 // hit tests.
     25 class TestDesktopNativeWidgetAura : public views::DesktopNativeWidgetAura {
     26  public:
     27   explicit TestDesktopNativeWidgetAura(
     28       views::internal::NativeWidgetDelegate* delegate)
     29       : views::DesktopNativeWidgetAura(delegate) {}
     30   virtual ~TestDesktopNativeWidgetAura() {}
     31 
     32   void set_window_component(int window_component) {
     33     window_component_ = window_component;
     34   }
     35 
     36   // DesktopNativeWidgetAura:
     37   virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
     38     return window_component_;
     39   }
     40 
     41  private:
     42   int window_component_;
     43 
     44   DISALLOW_COPY_AND_ASSIGN(TestDesktopNativeWidgetAura);
     45 };
     46 
     47 }  // namespace
     48 
     49 namespace views {
     50 
     51 const int64 kFirstDisplay = 5321829;
     52 const int64 kSecondDisplay = 928310;
     53 
     54 class DesktopScreenX11Test : public views::ViewsTestBase,
     55                              public gfx::DisplayObserver {
     56  public:
     57   DesktopScreenX11Test() {}
     58   virtual ~DesktopScreenX11Test() {}
     59 
     60   // Overridden from testing::Test:
     61   virtual void SetUp() OVERRIDE {
     62     ViewsTestBase::SetUp();
     63     // Initialize the world to the single monitor case.
     64     std::vector<gfx::Display> displays;
     65     displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
     66     screen_.reset(new DesktopScreenX11(displays));
     67     screen_->AddObserver(this);
     68   }
     69 
     70   virtual void TearDown() OVERRIDE {
     71     screen_.reset();
     72     ViewsTestBase::TearDown();
     73   }
     74 
     75  protected:
     76   std::vector<gfx::Display> changed_display_;
     77   std::vector<gfx::Display> added_display_;
     78   std::vector<gfx::Display> removed_display_;
     79 
     80   DesktopScreenX11* screen() { return screen_.get(); }
     81 
     82   void NotifyDisplaysChanged(const std::vector<gfx::Display>& displays) {
     83     DesktopScreenX11* screen = screen_.get();
     84     screen->change_notifier_.NotifyDisplaysChanged(screen->displays_, displays);
     85     screen->displays_ = displays;
     86   }
     87 
     88   void ResetDisplayChanges() {
     89     changed_display_.clear();
     90     added_display_.clear();
     91     removed_display_.clear();
     92   }
     93 
     94   Widget* BuildTopLevelDesktopWidget(const gfx::Rect& bounds,
     95       bool use_test_native_widget) {
     96     Widget* toplevel = new Widget;
     97     Widget::InitParams toplevel_params =
     98         CreateParams(Widget::InitParams::TYPE_WINDOW);
     99     if (use_test_native_widget) {
    100       toplevel_params.native_widget =
    101           new TestDesktopNativeWidgetAura(toplevel);
    102     } else {
    103       toplevel_params.native_widget =
    104           new views::DesktopNativeWidgetAura(toplevel);
    105     }
    106     toplevel_params.bounds = bounds;
    107     toplevel_params.remove_standard_frame = true;
    108     toplevel->Init(toplevel_params);
    109     return toplevel;
    110   }
    111 
    112  private:
    113   // Overridden from gfx::DisplayObserver:
    114   virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE {
    115     added_display_.push_back(new_display);
    116   }
    117 
    118   virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE {
    119     removed_display_.push_back(old_display);
    120   }
    121 
    122   virtual void OnDisplayMetricsChanged(const gfx::Display& display,
    123                                        uint32_t metrics) OVERRIDE {
    124     changed_display_.push_back(display);
    125   }
    126 
    127   scoped_ptr<DesktopScreenX11> screen_;
    128 
    129   DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11Test);
    130 };
    131 
    132 TEST_F(DesktopScreenX11Test, BoundsChangeSingleMonitor) {
    133   std::vector<gfx::Display> displays;
    134   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 1024, 768)));
    135   NotifyDisplaysChanged(displays);
    136 
    137   EXPECT_EQ(1u, changed_display_.size());
    138   EXPECT_EQ(0u, added_display_.size());
    139   EXPECT_EQ(0u, removed_display_.size());
    140 }
    141 
    142 TEST_F(DesktopScreenX11Test, AddMonitorToTheRight) {
    143   std::vector<gfx::Display> displays;
    144   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    145   displays.push_back(gfx::Display(kSecondDisplay,
    146                                   gfx::Rect(640, 0, 1024, 768)));
    147   NotifyDisplaysChanged(displays);
    148 
    149   EXPECT_EQ(0u, changed_display_.size());
    150   EXPECT_EQ(1u, added_display_.size());
    151   EXPECT_EQ(0u, removed_display_.size());
    152 }
    153 
    154 TEST_F(DesktopScreenX11Test, AddMonitorToTheLeft) {
    155   std::vector<gfx::Display> displays;
    156   displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768)));
    157   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(1024, 0, 640, 480)));
    158   NotifyDisplaysChanged(displays);
    159 
    160   EXPECT_EQ(1u, changed_display_.size());
    161   EXPECT_EQ(1u, added_display_.size());
    162   EXPECT_EQ(0u, removed_display_.size());
    163 }
    164 
    165 TEST_F(DesktopScreenX11Test, RemoveMonitorOnRight) {
    166   std::vector<gfx::Display> displays;
    167   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    168   displays.push_back(gfx::Display(kSecondDisplay,
    169                                   gfx::Rect(640, 0, 1024, 768)));
    170   NotifyDisplaysChanged(displays);
    171 
    172   ResetDisplayChanges();
    173 
    174   displays.clear();
    175   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    176   NotifyDisplaysChanged(displays);
    177 
    178   EXPECT_EQ(0u, changed_display_.size());
    179   EXPECT_EQ(0u, added_display_.size());
    180   EXPECT_EQ(1u, removed_display_.size());
    181 }
    182 
    183 TEST_F(DesktopScreenX11Test, RemoveMonitorOnLeft) {
    184   std::vector<gfx::Display> displays;
    185   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    186   displays.push_back(gfx::Display(kSecondDisplay,
    187                                   gfx::Rect(640, 0, 1024, 768)));
    188   NotifyDisplaysChanged(displays);
    189 
    190   ResetDisplayChanges();
    191 
    192   displays.clear();
    193   displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768)));
    194   NotifyDisplaysChanged(displays);
    195 
    196   EXPECT_EQ(1u, changed_display_.size());
    197   EXPECT_EQ(0u, added_display_.size());
    198   EXPECT_EQ(1u, removed_display_.size());
    199 }
    200 
    201 TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) {
    202   std::vector<gfx::Display> displays;
    203   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    204   displays.push_back(gfx::Display(kSecondDisplay,
    205                                   gfx::Rect(640, 0, 1024, 768)));
    206   NotifyDisplaysChanged(displays);
    207 
    208   EXPECT_EQ(kSecondDisplay,
    209             screen()->GetDisplayNearestPoint(gfx::Point(650, 10)).id());
    210   EXPECT_EQ(kFirstDisplay,
    211             screen()->GetDisplayNearestPoint(gfx::Point(10, 10)).id());
    212   EXPECT_EQ(kFirstDisplay,
    213             screen()->GetDisplayNearestPoint(gfx::Point(10000, 10000)).id());
    214 }
    215 
    216 TEST_F(DesktopScreenX11Test, GetDisplayMatchingBasic) {
    217   std::vector<gfx::Display> displays;
    218   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    219   displays.push_back(gfx::Display(kSecondDisplay,
    220                                   gfx::Rect(640, 0, 1024, 768)));
    221   NotifyDisplaysChanged(displays);
    222 
    223   EXPECT_EQ(kSecondDisplay,
    224             screen()->GetDisplayMatching(gfx::Rect(700, 20, 100, 100)).id());
    225 }
    226 
    227 TEST_F(DesktopScreenX11Test, GetDisplayMatchingOverlap) {
    228   std::vector<gfx::Display> displays;
    229   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    230   displays.push_back(gfx::Display(kSecondDisplay,
    231                                   gfx::Rect(640, 0, 1024, 768)));
    232   NotifyDisplaysChanged(displays);
    233 
    234   EXPECT_EQ(kSecondDisplay,
    235             screen()->GetDisplayMatching(gfx::Rect(630, 20, 100, 100)).id());
    236 }
    237 
    238 TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) {
    239   std::vector<gfx::Display> displays;
    240   displays.push_back(gfx::Display(kFirstDisplay,
    241                                   gfx::Rect(640, 0, 1024, 768)));
    242   displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 640, 480)));
    243   NotifyDisplaysChanged(displays);
    244 
    245   // The first display in the list is always the primary, even if other
    246   // displays are to the left in screen layout.
    247   EXPECT_EQ(kFirstDisplay, screen()->GetPrimaryDisplay().id());
    248 }
    249 
    250 TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) {
    251   // Set up a two monitor situation.
    252   std::vector<gfx::Display> displays;
    253   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    254   displays.push_back(gfx::Display(kSecondDisplay,
    255                                   gfx::Rect(640, 0, 1024, 768)));
    256   NotifyDisplaysChanged(displays);
    257 
    258   Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10),
    259       false);
    260   Widget* window_two = BuildTopLevelDesktopWidget(gfx::Rect(650, 50, 10, 10),
    261       false);
    262 
    263   EXPECT_EQ(
    264       kFirstDisplay,
    265       screen()->GetDisplayNearestWindow(window_one->GetNativeWindow()).id());
    266   EXPECT_EQ(
    267       kSecondDisplay,
    268       screen()->GetDisplayNearestWindow(window_two->GetNativeWindow()).id());
    269 
    270   window_one->CloseNow();
    271   window_two->CloseNow();
    272 }
    273 
    274 // Tests that the window is maximized in response to a double click event.
    275 TEST_F(DesktopScreenX11Test, DoubleClickHeaderMaximizes) {
    276   if (!ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")))
    277     return;
    278 
    279   Widget* widget = BuildTopLevelDesktopWidget(gfx::Rect(0, 0, 100, 100), true);
    280   widget->Show();
    281   TestDesktopNativeWidgetAura* native_widget =
    282       static_cast<TestDesktopNativeWidgetAura*>(widget->native_widget());
    283   native_widget->set_window_component(HTCAPTION);
    284 
    285   aura::Window* window = widget->GetNativeWindow();
    286   window->SetProperty(aura::client::kCanMaximizeKey, true);
    287 
    288   // Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
    289   DesktopWindowTreeHost* rwh =
    290       DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
    291           GetAcceleratedWidget());
    292 
    293   ui::test::EventGenerator generator(window);
    294   generator.ClickLeftButton();
    295   generator.DoubleClickLeftButton();
    296   RunPendingMessages();
    297   EXPECT_TRUE(rwh->IsMaximized());
    298 
    299   widget->CloseNow();
    300 }
    301 
    302 // Tests that the window does not maximize in response to a double click event,
    303 // if the first click was to a different target component than that of the
    304 // second click.
    305 TEST_F(DesktopScreenX11Test, DoubleClickTwoDifferentTargetsDoesntMaximizes) {
    306   Widget* widget = BuildTopLevelDesktopWidget(gfx::Rect(0, 0, 100, 100), true);
    307   widget->Show();
    308   TestDesktopNativeWidgetAura* native_widget =
    309       static_cast<TestDesktopNativeWidgetAura*>(widget->native_widget());
    310 
    311   aura::Window* window = widget->GetNativeWindow();
    312   window->SetProperty(aura::client::kCanMaximizeKey, true);
    313 
    314   // Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
    315   DesktopWindowTreeHost* rwh =
    316       DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
    317           GetAcceleratedWidget());
    318 
    319   ui::test::EventGenerator generator(window);
    320   native_widget->set_window_component(HTCLIENT);
    321   generator.ClickLeftButton();
    322   native_widget->set_window_component(HTCAPTION);
    323   generator.DoubleClickLeftButton();
    324   RunPendingMessages();
    325   EXPECT_FALSE(rwh->IsMaximized());
    326 
    327   widget->CloseNow();
    328 }
    329 
    330 // Tests that the window does not maximize in response to a double click event,
    331 // if the double click was interrupted by a right click.
    332 TEST_F(DesktopScreenX11Test, RightClickDuringDoubleClickDoesntMaximize) {
    333   Widget* widget = BuildTopLevelDesktopWidget(gfx::Rect(0, 0, 100, 100), true);
    334   widget->Show();
    335   TestDesktopNativeWidgetAura* native_widget =
    336       static_cast<TestDesktopNativeWidgetAura*>(widget->native_widget());
    337 
    338   aura::Window* window = widget->GetNativeWindow();
    339   window->SetProperty(aura::client::kCanMaximizeKey, true);
    340 
    341   // Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
    342   DesktopWindowTreeHost* rwh = static_cast<DesktopWindowTreeHost*>(
    343       DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
    344           GetAcceleratedWidget()));
    345 
    346   ui::test::EventGenerator generator(window);
    347   native_widget->set_window_component(HTCLIENT);
    348   generator.ClickLeftButton();
    349   native_widget->set_window_component(HTCAPTION);
    350   generator.PressRightButton();
    351   generator.ReleaseRightButton();
    352   EXPECT_FALSE(rwh->IsMaximized());
    353   generator.DoubleClickLeftButton();
    354   RunPendingMessages();
    355   EXPECT_FALSE(rwh->IsMaximized());
    356 
    357   widget->CloseNow();
    358 }
    359 
    360 // Test that rotating the displays notifies the DisplayObservers.
    361 TEST_F(DesktopScreenX11Test, RotationChange) {
    362   std::vector<gfx::Display> displays;
    363   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    364   displays.push_back(
    365       gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
    366   NotifyDisplaysChanged(displays);
    367   ResetDisplayChanges();
    368 
    369   displays[0].set_rotation(gfx::Display::ROTATE_90);
    370   NotifyDisplaysChanged(displays);
    371   EXPECT_EQ(1u, changed_display_.size());
    372 
    373   displays[1].set_rotation(gfx::Display::ROTATE_90);
    374   NotifyDisplaysChanged(displays);
    375   EXPECT_EQ(2u, changed_display_.size());
    376 
    377   displays[0].set_rotation(gfx::Display::ROTATE_270);
    378   NotifyDisplaysChanged(displays);
    379   EXPECT_EQ(3u, changed_display_.size());
    380 
    381   displays[0].set_rotation(gfx::Display::ROTATE_270);
    382   NotifyDisplaysChanged(displays);
    383   EXPECT_EQ(3u, changed_display_.size());
    384 
    385   displays[0].set_rotation(gfx::Display::ROTATE_0);
    386   displays[1].set_rotation(gfx::Display::ROTATE_0);
    387   NotifyDisplaysChanged(displays);
    388   EXPECT_EQ(5u, changed_display_.size());
    389 }
    390 
    391 // Test that changing the displays workarea notifies the DisplayObservers.
    392 TEST_F(DesktopScreenX11Test, WorkareaChange) {
    393   std::vector<gfx::Display> displays;
    394   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    395   displays.push_back(
    396       gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
    397   NotifyDisplaysChanged(displays);
    398   ResetDisplayChanges();
    399 
    400   displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
    401   NotifyDisplaysChanged(displays);
    402   EXPECT_EQ(1u, changed_display_.size());
    403 
    404   displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
    405   NotifyDisplaysChanged(displays);
    406   EXPECT_EQ(2u, changed_display_.size());
    407 
    408   displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
    409   NotifyDisplaysChanged(displays);
    410   EXPECT_EQ(2u, changed_display_.size());
    411 
    412   displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
    413   NotifyDisplaysChanged(displays);
    414   EXPECT_EQ(2u, changed_display_.size());
    415 
    416   displays[0].set_work_area(gfx::Rect(0, 0, 640, 480));
    417   displays[1].set_work_area(gfx::Rect(640, 0, 1024, 768));
    418   NotifyDisplaysChanged(displays);
    419   EXPECT_EQ(4u, changed_display_.size());
    420 }
    421 
    422 // Test that changing the device scale factor notifies the DisplayObservers.
    423 TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) {
    424   std::vector<gfx::Display> displays;
    425   displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
    426   displays.push_back(
    427       gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
    428   NotifyDisplaysChanged(displays);
    429   ResetDisplayChanges();
    430 
    431   displays[0].set_device_scale_factor(2.5f);
    432   NotifyDisplaysChanged(displays);
    433   EXPECT_EQ(1u, changed_display_.size());
    434 
    435   displays[1].set_device_scale_factor(2.5f);
    436   NotifyDisplaysChanged(displays);
    437   EXPECT_EQ(2u, changed_display_.size());
    438 
    439   displays[0].set_device_scale_factor(2.5f);
    440   NotifyDisplaysChanged(displays);
    441   EXPECT_EQ(2u, changed_display_.size());
    442 
    443   displays[1].set_device_scale_factor(2.5f);
    444   NotifyDisplaysChanged(displays);
    445   EXPECT_EQ(2u, changed_display_.size());
    446 
    447   displays[0].set_device_scale_factor(1.f);
    448   displays[1].set_device_scale_factor(1.f);
    449   NotifyDisplaysChanged(displays);
    450   EXPECT_EQ(4u, changed_display_.size());
    451 }
    452 
    453 }  // namespace views
    454