| Index: ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
|
| diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
|
| index 1c14861b13c96ea5fdf14ca8b17d28515cd95956..52798d4551296182479aa940973fd2bfc5a949c6 100644
|
| --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
|
| +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
|
| @@ -2,8 +2,9 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include <vector>
|
| +#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
|
|
|
| +#include <vector>
|
| #include <X11/Xlib.h>
|
|
|
| // Get rid of X11 macros which conflict with gtest.
|
| @@ -12,11 +13,13 @@
|
|
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/path_service.h"
|
| +#include "ui/aura/env.h"
|
| #include "ui/aura/window.h"
|
| #include "ui/aura/window_tree_host.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
| #include "ui/base/ui_base_paths.h"
|
| #include "ui/base/x/x11_util.h"
|
| +#include "ui/events/event_handler.h"
|
| #include "ui/events/platform/x11/x11_event_source.h"
|
| #include "ui/gfx/rect.h"
|
| #include "ui/gfx/x/x11_atom_cache.h"
|
| @@ -24,6 +27,7 @@
|
| #include "ui/views/test/views_test_base.h"
|
| #include "ui/views/test/x11_property_change_waiter.h"
|
| #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
|
| +#include "ui/views/widget/desktop_aura/x11_capture_window.h"
|
|
|
| namespace views {
|
|
|
| @@ -53,25 +57,85 @@ class ActivationWaiter : public X11PropertyChangeWaiter {
|
| DISALLOW_COPY_AND_ASSIGN(ActivationWaiter);
|
| };
|
|
|
| -// Creates a widget of size 100x100.
|
| -scoped_ptr<Widget> CreateWidget() {
|
| +// An event handler which counts the number of mouse moves it has seen.
|
| +class MouseMoveCounterHandler : public ui::EventHandler {
|
| + public:
|
| + MouseMoveCounterHandler() : count_(0) {
|
| + }
|
| + virtual ~MouseMoveCounterHandler() {
|
| + }
|
| +
|
| + // ui::EventHandler:
|
| + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
|
| + if (event->type() == ui::ET_MOUSE_MOVED)
|
| + ++count_;
|
| + }
|
| +
|
| + int num_mouse_moves() const {
|
| + return count_;
|
| + }
|
| +
|
| + private:
|
| + int count_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MouseMoveCounterHandler);
|
| +};
|
| +
|
| +// Creates a widget with the given bounds.
|
| +scoped_ptr<Widget> CreateWidget(const gfx::Rect& bounds) {
|
| scoped_ptr<Widget> widget(new Widget);
|
| Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
|
| params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
| params.remove_standard_frame = true;
|
| params.native_widget = new DesktopNativeWidgetAura(widget.get());
|
| - params.bounds = gfx::Rect(100, 100, 100, 100);
|
| + params.bounds = bounds;
|
| widget->Init(params);
|
| return widget.Pass();
|
| }
|
|
|
| +// Creates an XMotionEvent targeted to |xid| with location |point_in_screen|.
|
| +// Does not dispatch the event.
|
| +XEvent CreateMouseMotionEvent(
|
| + XID xid,
|
| + const gfx::Rect& xid_bounds_in_screen,
|
| + const gfx::Point& point_in_screen) {
|
| + Display* display = gfx::GetXDisplay();
|
| + XEvent xev;
|
| + xev.xmotion.type = MotionNotify;
|
| + xev.xmotion.display = display;
|
| + xev.xmotion.window = xid;
|
| + xev.xmotion.root = DefaultRootWindow(display);
|
| + xev.xmotion.subwindow = 0;
|
| + xev.xmotion.time = CurrentTime;
|
| + xev.xmotion.x = point_in_screen.x() - xid_bounds_in_screen.x();
|
| + xev.xmotion.y = point_in_screen.y() - xid_bounds_in_screen.y();
|
| + xev.xmotion.x_root = point_in_screen.x();
|
| + xev.xmotion.y_root = point_in_screen.y();
|
| + xev.xmotion.state = 0;
|
| + xev.xmotion.is_hint = NotifyNormal;
|
| + xev.xmotion.same_screen = True;
|
| + return xev;
|
| +}
|
| +
|
| +// Dispatch event to |hosts|.
|
| +void DispatchEvent(
|
| + const ui::PlatformEvent& event,
|
| + const std::vector<DesktopWindowTreeHostX11*>& hosts) {
|
| + for (size_t i = 0; i < hosts.size(); ++i) {
|
| + ui::PlatformEventDispatcher* dispatcher =
|
| + static_cast<ui::PlatformEventDispatcher*>(hosts[i]);
|
| + if (dispatcher->CanDispatchEvent(event))
|
| + dispatcher->DispatchEvent(event);
|
| + }
|
| +}
|
| +
|
| } // namespace
|
|
|
| -class DesktopWindowTreeHostX11Test : public ViewsTestBase {
|
| +class DesktopWindowTreeHostX11InteractiveUITest : public ViewsTestBase {
|
| public:
|
| - DesktopWindowTreeHostX11Test() {
|
| + DesktopWindowTreeHostX11InteractiveUITest() {
|
| }
|
| - virtual ~DesktopWindowTreeHostX11Test() {
|
| + virtual ~DesktopWindowTreeHostX11InteractiveUITest() {
|
| }
|
|
|
| static void SetUpTestCase() {
|
| @@ -82,6 +146,7 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase {
|
| ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
|
| }
|
|
|
| + // testing::Test
|
| virtual void SetUp() OVERRIDE {
|
| ViewsTestBase::SetUp();
|
|
|
| @@ -96,14 +161,14 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase {
|
| }
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test);
|
| + DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11InteractiveUITest);
|
| };
|
|
|
| // Test that calling Widget::Deactivate() sets the widget as inactive wrt to
|
| // Chrome even if it not possible to deactivate the window wrt to the x server.
|
| // This behavior is required by several interactive_ui_tests.
|
| -TEST_F(DesktopWindowTreeHostX11Test, Deactivate) {
|
| - scoped_ptr<Widget> widget(CreateWidget());
|
| +TEST_F(DesktopWindowTreeHostX11InteractiveUITest, Deactivate) {
|
| + scoped_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100)));
|
|
|
| ActivationWaiter waiter(
|
| widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
|
| @@ -124,4 +189,120 @@ TEST_F(DesktopWindowTreeHostX11Test, Deactivate) {
|
| EXPECT_TRUE(widget->IsActive());
|
| }
|
|
|
| +// Chrome attempts to make mouse capture look synchronous on Linux. Test that
|
| +// Chrome synchronously switches the window that mouse events are forwarded to
|
| +// when capture is changed.
|
| +TEST_F(DesktopWindowTreeHostX11InteractiveUITest, SynchronousCapture) {
|
| + scoped_ptr<Widget> widget1(CreateWidget(gfx::Rect(100, 100, 100, 100)));
|
| + aura::Window* window1 = widget1->GetNativeWindow();
|
| + DesktopWindowTreeHostX11* host1 =
|
| + static_cast<DesktopWindowTreeHostX11*>(window1->GetHost());
|
| + widget1->Show();
|
| + gfx::Rect widget1_bounds_in_screen = widget1->GetWindowBoundsInScreen();
|
| +
|
| + scoped_ptr<Widget> widget2(CreateWidget(gfx::Rect(200, 100, 100, 100)));
|
| + aura::Window* window2 = widget2->GetNativeWindow();
|
| + DesktopWindowTreeHostX11* host2 =
|
| + static_cast<DesktopWindowTreeHostX11*>(window2->GetHost());
|
| + XID widget2_xid = host2->GetAcceleratedWidget();
|
| + widget2->Show();
|
| + gfx::Rect widget2_bounds_in_screen = widget2->GetWindowBoundsInScreen();
|
| +
|
| + std::vector<DesktopWindowTreeHostX11*> hosts;
|
| + hosts.push_back(host1);
|
| + hosts.push_back(host2);
|
| +
|
| + MouseMoveCounterHandler recorder1;
|
| + window1->AddPreTargetHandler(&recorder1);
|
| + MouseMoveCounterHandler recorder2;
|
| + window2->AddPreTargetHandler(&recorder2);
|
| +
|
| + // Move the mouse to the center of |widget2|.
|
| + gfx::Point point_in_screen = widget2_bounds_in_screen.CenterPoint();
|
| + XEvent motion_event = CreateMouseMotionEvent(
|
| + widget2_xid, widget2_bounds_in_screen, point_in_screen);
|
| + DispatchEvent(&motion_event, hosts);
|
| + EXPECT_EQ(0, recorder1.num_mouse_moves());
|
| + EXPECT_EQ(1, recorder2.num_mouse_moves());
|
| + EXPECT_EQ(point_in_screen.ToString(),
|
| + aura::Env::GetInstance()->last_mouse_location().ToString());
|
| +
|
| + // Set capture to |widget1|. Because X11CaptureWindow calls XGrabPointer()
|
| + // with owner == False, the X server sends events to |widget2| as long as the
|
| + // mouse is hovered over |widget2|. Verify that Chrome redirects mouse events
|
| + // to |widget1|.
|
| + widget1->SetCapture(NULL);
|
| + point_in_screen += gfx::Vector2d(1, 0);
|
| + motion_event = CreateMouseMotionEvent(
|
| + widget2_xid, widget2_bounds_in_screen, point_in_screen);
|
| + DispatchEvent(&motion_event, hosts);
|
| + EXPECT_EQ(1, recorder1.num_mouse_moves());
|
| + EXPECT_EQ(1, recorder2.num_mouse_moves());
|
| + // If the event's location was correctly changed to be relative to |widget1|,
|
| + // Env's last mouse position will be correct.
|
| + EXPECT_EQ(point_in_screen.ToString(),
|
| + aura::Env::GetInstance()->last_mouse_location().ToString());
|
| +
|
| + // Set capture to |widget2|. Chrome should forward subsequent events to
|
| + // |widget2|.
|
| + widget2->SetCapture(NULL);
|
| + point_in_screen += gfx::Vector2d(1, 0);
|
| + motion_event = CreateMouseMotionEvent(
|
| + widget2_xid, widget2_bounds_in_screen, point_in_screen);
|
| + DispatchEvent(&motion_event, hosts);
|
| + EXPECT_EQ(1, recorder1.num_mouse_moves());
|
| + EXPECT_EQ(2, recorder2.num_mouse_moves());
|
| + EXPECT_EQ(point_in_screen.ToString(),
|
| + aura::Env::GetInstance()->last_mouse_location().ToString());
|
| +
|
| + // If the mouse is not hovered over |widget1| or |widget2|, the X server will
|
| + // send events to X11CaptureWindow's window. Verify that Chrome redirects
|
| + // mouse events to |widget2|.
|
| + ASSERT_TRUE(host2->capture_window_.get() != NULL);
|
| + XID capture_window_xid = host2->capture_window_->xwindow();
|
| + gfx::Rect capture_window_bounds_in_screen;
|
| + ui::GetWindowRect(capture_window_xid, &capture_window_bounds_in_screen);
|
| +
|
| + point_in_screen = gfx::Point();
|
| + motion_event = CreateMouseMotionEvent(
|
| + capture_window_xid, capture_window_bounds_in_screen, point_in_screen);
|
| + DispatchEvent(&motion_event, hosts);
|
| + EXPECT_EQ(1, recorder1.num_mouse_moves());
|
| + EXPECT_EQ(3, recorder2.num_mouse_moves());
|
| + EXPECT_EQ(point_in_screen.ToString(),
|
| + aura::Env::GetInstance()->last_mouse_location().ToString());
|
| +
|
| + // Set capture to |widget1|. Chrome should redirect mouse events from
|
| + // the X11CaptureWindow to |widget1|.
|
| + widget1->SetCapture(NULL);
|
| + EXPECT_EQ(NULL, host2->capture_window_.get());
|
| + ASSERT_TRUE(host1->capture_window_.get() != NULL);
|
| + EXPECT_EQ(capture_window_xid, host1->capture_window_->xwindow());
|
| +
|
| + point_in_screen += gfx::Vector2d(1, 0);
|
| + motion_event = CreateMouseMotionEvent(
|
| + capture_window_xid, capture_window_bounds_in_screen, point_in_screen);
|
| + DispatchEvent(&motion_event, hosts);
|
| + EXPECT_EQ(2, recorder1.num_mouse_moves());
|
| + EXPECT_EQ(3, recorder2.num_mouse_moves());
|
| + EXPECT_EQ(point_in_screen.ToString(),
|
| + aura::Env::GetInstance()->last_mouse_location().ToString());
|
| +
|
| + // Release capture. Test that when capture is released, mouse events are no
|
| + // longer forwarded to other widgets.
|
| + widget1->ReleaseCapture();
|
| + point_in_screen = widget2_bounds_in_screen.CenterPoint();
|
| + motion_event = CreateMouseMotionEvent(
|
| + widget2_xid, widget2_bounds_in_screen, point_in_screen);
|
| + DispatchEvent(&motion_event, hosts);
|
| + EXPECT_EQ(2, recorder1.num_mouse_moves());
|
| + EXPECT_EQ(4, recorder2.num_mouse_moves());
|
| + EXPECT_EQ(point_in_screen.ToString(),
|
| + aura::Env::GetInstance()->last_mouse_location().ToString());
|
| +
|
| + // Cleanup
|
| + window1->RemovePreTargetHandler(&recorder1);
|
| + window2->RemovePreTargetHandler(&recorder2);
|
| +}
|
| +
|
| } // namespace views
|
|
|