Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / views / widget / desktop_aura / desktop_window_tree_host_x11_interactive_uitest.cc
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 "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
6
7 #include <X11/Xlib.h>
8
9 // Get rid of X11 macros which conflict with gtest.
10 #undef Bool
11 #undef None
12
13 #include "base/memory/scoped_ptr.h"
14 #include "base/path_service.h"
15 #include "ui/aura/env.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/base/ui_base_paths.h"
20 #include "ui/base/x/x11_util.h"
21 #include "ui/events/event_handler.h"
22 #include "ui/events/platform/x11/x11_event_source.h"
23 #include "ui/gfx/rect.h"
24 #include "ui/gfx/x/x11_atom_cache.h"
25 #include "ui/gl/gl_surface.h"
26 #include "ui/views/test/views_test_base.h"
27 #include "ui/views/test/x11_property_change_waiter.h"
28 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
29
30 namespace views {
31
32 namespace {
33
34 // Blocks till |window| gets activated.
35 class ActivationWaiter : public X11PropertyChangeWaiter {
36  public:
37   explicit ActivationWaiter(XID window)
38       : X11PropertyChangeWaiter(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW"),
39         window_(window) {
40   }
41
42   ~ActivationWaiter() override {}
43
44  private:
45   // X11PropertyChangeWaiter:
46   bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override {
47     XID xid = 0;
48     ui::GetXIDProperty(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW", &xid);
49     return xid != window_;
50   }
51
52   XID window_;
53
54   DISALLOW_COPY_AND_ASSIGN(ActivationWaiter);
55 };
56
57 // An event handler which counts the number of mouse moves it has seen.
58 class MouseMoveCounterHandler : public ui::EventHandler {
59  public:
60   MouseMoveCounterHandler() : count_(0) {
61   }
62   ~MouseMoveCounterHandler() override {}
63
64   // ui::EventHandler:
65   void OnMouseEvent(ui::MouseEvent* event) override {
66     if (event->type() == ui::ET_MOUSE_MOVED)
67       ++count_;
68   }
69
70   int num_mouse_moves() const {
71     return count_;
72   }
73
74  private:
75   int count_;
76
77   DISALLOW_COPY_AND_ASSIGN(MouseMoveCounterHandler);
78 };
79
80 // Creates a widget with the given bounds.
81 scoped_ptr<Widget> CreateWidget(const gfx::Rect& bounds) {
82   scoped_ptr<Widget> widget(new Widget);
83   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
84   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
85   params.remove_standard_frame = true;
86   params.native_widget = new DesktopNativeWidgetAura(widget.get());
87   params.bounds = bounds;
88   widget->Init(params);
89   return widget.Pass();
90 }
91
92 // Dispatches an XMotionEvent targeted at |host|'s X window with location
93 // |point_in_screen|.
94 void DispatchMouseMotionEvent(DesktopWindowTreeHostX11* desktop_host,
95                               const gfx::Point& point_in_screen) {
96   aura::WindowTreeHost* host = static_cast<aura::WindowTreeHost*>(desktop_host);
97   gfx::Rect bounds_in_screen = desktop_host->window()->GetBoundsInScreen();
98
99   Display* display = gfx::GetXDisplay();
100   XEvent xev;
101   xev.xmotion.type = MotionNotify;
102   xev.xmotion.display = display;
103   xev.xmotion.window = host->GetAcceleratedWidget();
104   xev.xmotion.root = DefaultRootWindow(display);
105   xev.xmotion.subwindow = 0;
106   xev.xmotion.time = CurrentTime;
107   xev.xmotion.x = point_in_screen.x() - bounds_in_screen.x();
108   xev.xmotion.y = point_in_screen.y() - bounds_in_screen.y();
109   xev.xmotion.x_root = point_in_screen.x();
110   xev.xmotion.y_root = point_in_screen.y();
111   xev.xmotion.state = 0;
112   xev.xmotion.is_hint = NotifyNormal;
113   xev.xmotion.same_screen = True;
114
115   static_cast<ui::PlatformEventDispatcher*>(desktop_host)->DispatchEvent(&xev);
116 }
117
118 }  // namespace
119
120 class DesktopWindowTreeHostX11Test : public ViewsTestBase {
121  public:
122   DesktopWindowTreeHostX11Test() {
123   }
124   ~DesktopWindowTreeHostX11Test() override {}
125
126   static void SetUpTestCase() {
127     gfx::GLSurface::InitializeOneOffForTests();
128     ui::RegisterPathProvider();
129     base::FilePath ui_test_pak_path;
130     ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
131     ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
132   }
133
134   // testing::Test
135   void SetUp() override {
136     ViewsTestBase::SetUp();
137
138     // Make X11 synchronous for our display connection. This does not force the
139     // window manager to behave synchronously.
140     XSynchronize(gfx::GetXDisplay(), True);
141   }
142
143   void TearDown() override {
144     XSynchronize(gfx::GetXDisplay(), False);
145     ViewsTestBase::TearDown();
146   }
147
148  private:
149   DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test);
150 };
151
152 // Test that calling Widget::Deactivate() sets the widget as inactive wrt to
153 // Chrome even if it not possible to deactivate the window wrt to the x server.
154 // This behavior is required by several interactive_ui_tests.
155 TEST_F(DesktopWindowTreeHostX11Test, Deactivate) {
156   scoped_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100)));
157
158   ActivationWaiter waiter(
159       widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
160   widget->Show();
161   widget->Activate();
162   waiter.Wait();
163
164   widget->Deactivate();
165   // Regardless of whether |widget|'s X11 window eventually gets deactivated,
166   // |widget|'s "active" state should change.
167   EXPECT_FALSE(widget->IsActive());
168
169   // |widget|'s X11 window should still be active. Reactivating |widget| should
170   // update the widget's "active" state.
171   // Note: Activating a widget whose X11 window is not active does not
172   // synchronously update the widget's "active" state.
173   widget->Activate();
174   EXPECT_TRUE(widget->IsActive());
175 }
176
177 // Chrome attempts to make mouse capture look synchronous on Linux. Test that
178 // Chrome synchronously switches the window that mouse events are forwarded to
179 // when capture is changed.
180 TEST_F(DesktopWindowTreeHostX11Test, CaptureEventForwarding) {
181   scoped_ptr<Widget> widget1(CreateWidget(gfx::Rect(100, 100, 100, 100)));
182   aura::Window* window1 = widget1->GetNativeWindow();
183   DesktopWindowTreeHostX11* host1 =
184       static_cast<DesktopWindowTreeHostX11*>(window1->GetHost());
185   widget1->Show();
186
187   scoped_ptr<Widget> widget2(CreateWidget(gfx::Rect(200, 100, 100, 100)));
188   aura::Window* window2 = widget2->GetNativeWindow();
189   DesktopWindowTreeHostX11* host2 =
190       static_cast<DesktopWindowTreeHostX11*>(window2->GetHost());
191   widget2->Show();
192
193   MouseMoveCounterHandler recorder1;
194   window1->AddPreTargetHandler(&recorder1);
195   MouseMoveCounterHandler recorder2;
196   window2->AddPreTargetHandler(&recorder2);
197
198   // Move the mouse to the center of |widget2|.
199   gfx::Point point_in_screen = widget2->GetWindowBoundsInScreen().CenterPoint();
200   DispatchMouseMotionEvent(host2, point_in_screen);
201   EXPECT_EQ(0, recorder1.num_mouse_moves());
202   EXPECT_EQ(1, recorder2.num_mouse_moves());
203   EXPECT_EQ(point_in_screen.ToString(),
204             aura::Env::GetInstance()->last_mouse_location().ToString());
205
206   // Set capture to |widget1|. Because DesktopWindowTreeHostX11 calls
207   // XGrabPointer() with owner == False, the X server sends events to |widget2|
208   // as long as the mouse is hovered over |widget2|. Verify that Chrome
209   // redirects mouse events to |widget1|.
210   widget1->SetCapture(NULL);
211   point_in_screen += gfx::Vector2d(1, 0);
212   DispatchMouseMotionEvent(host2, point_in_screen);
213   EXPECT_EQ(1, recorder1.num_mouse_moves());
214   EXPECT_EQ(1, recorder2.num_mouse_moves());
215   // If the event's location was correctly changed to be relative to |widget1|,
216   // Env's last mouse position will be correct.
217   EXPECT_EQ(point_in_screen.ToString(),
218             aura::Env::GetInstance()->last_mouse_location().ToString());
219
220   // Set capture to |widget2|. Subsequent events sent to |widget2| should not be
221   // forwarded.
222   widget2->SetCapture(NULL);
223   point_in_screen += gfx::Vector2d(1, 0);
224   DispatchMouseMotionEvent(host2, point_in_screen);
225   EXPECT_EQ(1, recorder1.num_mouse_moves());
226   EXPECT_EQ(2, recorder2.num_mouse_moves());
227   EXPECT_EQ(point_in_screen.ToString(),
228             aura::Env::GetInstance()->last_mouse_location().ToString());
229
230   // If the mouse is not hovered over |widget1| or |widget2|, the X server will
231   // send events to the window which has capture. Test the mouse events sent to
232   // |widget2| are not forwarded.
233   DispatchMouseMotionEvent(host2, point_in_screen);
234   EXPECT_EQ(1, recorder1.num_mouse_moves());
235   EXPECT_EQ(3, recorder2.num_mouse_moves());
236   EXPECT_EQ(point_in_screen.ToString(),
237             aura::Env::GetInstance()->last_mouse_location().ToString());
238
239   // Release capture. Test that when capture is released, mouse events are no
240   // longer forwarded to other widgets.
241   widget2->ReleaseCapture();
242   point_in_screen = widget1->GetWindowBoundsInScreen().CenterPoint();
243   DispatchMouseMotionEvent(host1, point_in_screen);
244   EXPECT_EQ(2, recorder1.num_mouse_moves());
245   EXPECT_EQ(3, recorder2.num_mouse_moves());
246   EXPECT_EQ(point_in_screen.ToString(),
247             aura::Env::GetInstance()->last_mouse_location().ToString());
248
249   // Cleanup
250   window1->RemovePreTargetHandler(&recorder1);
251   window2->RemovePreTargetHandler(&recorder2);
252 }
253
254 }  // namespace views