1 // Copyright 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/test/ui_controls_factory_desktop_aurax11.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/check_op.h"
12 #include "base/location.h"
13 #include "base/macros.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "ui/aura/client/screen_position_client.h"
17 #include "ui/aura/env.h"
18 #include "ui/aura/test/aura_test_utils.h"
19 #include "ui/aura/test/ui_controls_factory_aura.h"
20 #include "ui/aura/window_event_dispatcher.h"
21 #include "ui/base/test/ui_controls_aura.h"
22 #include "ui/base/x/test/x11_ui_controls_test_helper.h"
23 #include "ui/views/test/test_desktop_screen_x11.h"
24 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
25
26 namespace views {
27 namespace test {
28 namespace {
29
30 using ui_controls::DOWN;
31 using ui_controls::LEFT;
32 using ui_controls::MIDDLE;
33 using ui_controls::MouseButton;
34 using ui_controls::RIGHT;
35 using ui_controls::UIControlsAura;
36 using ui_controls::UP;
37
38 class UIControlsDesktopX11 : public UIControlsAura {
39 public:
40 UIControlsDesktopX11() = default;
41 ~UIControlsDesktopX11() override = default;
42
SendKeyPress(gfx::NativeWindow window,ui::KeyboardCode key,bool control,bool shift,bool alt,bool command)43 bool SendKeyPress(gfx::NativeWindow window,
44 ui::KeyboardCode key,
45 bool control,
46 bool shift,
47 bool alt,
48 bool command) override {
49 DCHECK(!command); // No command key on Aura
50 return SendKeyPressNotifyWhenDone(window, key, control, shift, alt, command,
51 base::OnceClosure());
52 }
53
SendKeyPressNotifyWhenDone(gfx::NativeWindow window,ui::KeyboardCode key,bool control,bool shift,bool alt,bool command,base::OnceClosure closure)54 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
55 ui::KeyboardCode key,
56 bool control,
57 bool shift,
58 bool alt,
59 bool command,
60 base::OnceClosure closure) override {
61 DCHECK(!command); // No command key on Aura
62
63 aura::WindowTreeHost* host = window->GetHost();
64 x11_ui_controls_test_helper_.SendKeyPressEvent(host->GetAcceleratedWidget(),
65 key, control, shift, alt,
66 command, std::move(closure));
67 return true;
68 }
69
SendMouseMove(int screen_x,int screen_y)70 bool SendMouseMove(int screen_x, int screen_y) override {
71 return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::OnceClosure());
72 }
SendMouseMoveNotifyWhenDone(int screen_x,int screen_y,base::OnceClosure closure)73 bool SendMouseMoveNotifyWhenDone(int screen_x,
74 int screen_y,
75 base::OnceClosure closure) override {
76 gfx::Point screen_location(screen_x, screen_y);
77 gfx::Point root_location = screen_location;
78 aura::Window* root_window = RootWindowForPoint(screen_location);
79
80 aura::client::ScreenPositionClient* screen_position_client =
81 aura::client::GetScreenPositionClient(root_window);
82 if (screen_position_client) {
83 screen_position_client->ConvertPointFromScreen(root_window,
84 &root_location);
85 }
86
87 aura::WindowTreeHost* host = root_window->GetHost();
88 gfx::Point root_current_location =
89 aura::test::QueryLatestMousePositionRequestInHost(host);
90 host->ConvertPixelsToDIP(&root_current_location);
91
92 auto* screen = views::test::TestDesktopScreenX11::GetInstance();
93 DCHECK_EQ(screen, display::Screen::GetScreen());
94 screen->set_cursor_screen_point(gfx::Point(screen_x, screen_y));
95
96 if (root_location != root_current_location &&
97 x11_ui_controls_test_helper_.ButtonDownMask() == 0) {
98 // Move the cursor because EnterNotify/LeaveNotify are generated with the
99 // current mouse position as a result of XGrabPointer()
100 root_window->MoveCursorTo(root_location);
101 } else {
102 gfx::Point screen_point(root_location);
103 host->ConvertDIPToScreenInPixels(&screen_point);
104 x11_ui_controls_test_helper_.SendMouseMotionNotifyEvent(
105 host->GetAcceleratedWidget(), root_location, screen_point,
106 std::move(closure));
107 }
108 x11_ui_controls_test_helper_.RunClosureAfterAllPendingUIEvents(
109 std::move(closure));
110 return true;
111 }
SendMouseEvents(MouseButton type,int button_state,int accelerator_state)112 bool SendMouseEvents(MouseButton type,
113 int button_state,
114 int accelerator_state) override {
115 return SendMouseEventsNotifyWhenDone(
116 type, button_state, base::OnceClosure(), accelerator_state);
117 }
SendMouseEventsNotifyWhenDone(MouseButton type,int button_state,base::OnceClosure closure,int accelerator_state)118 bool SendMouseEventsNotifyWhenDone(MouseButton type,
119 int button_state,
120 base::OnceClosure closure,
121 int accelerator_state) override {
122 gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location();
123 aura::Window* root_window = RootWindowForPoint(mouse_loc);
124 aura::client::ScreenPositionClient* screen_position_client =
125 aura::client::GetScreenPositionClient(root_window);
126 if (screen_position_client)
127 screen_position_client->ConvertPointFromScreen(root_window, &mouse_loc);
128
129 gfx::Point mouse_root_loc = mouse_loc;
130 root_window->GetHost()->ConvertDIPToScreenInPixels(&mouse_root_loc);
131 x11_ui_controls_test_helper_.SendMouseEvent(
132 root_window->GetHost()->GetAcceleratedWidget(), type, button_state,
133 accelerator_state, mouse_loc, mouse_root_loc, std::move(closure));
134 return true;
135 }
SendMouseClick(MouseButton type)136 bool SendMouseClick(MouseButton type) override {
137 return SendMouseEvents(type, UP | DOWN, ui_controls::kNoAccelerator);
138 }
139
140 private:
RootWindowForPoint(const gfx::Point & point)141 aura::Window* RootWindowForPoint(const gfx::Point& point) {
142 // Most interactive_ui_tests run inside of the aura_test_helper
143 // environment. This means that we can't rely on display::Screen and several
144 // other things to work properly. Therefore we hack around this by
145 // iterating across the windows owned DesktopWindowTreeHostLinux since this
146 // doesn't rely on having a DesktopScreenX11.
147 std::vector<aura::Window*> windows =
148 DesktopWindowTreeHostLinux::GetAllOpenWindows();
149 const auto i =
150 std::find_if(windows.cbegin(), windows.cend(), [point](auto* window) {
151 return window->GetBoundsInScreen().Contains(point) ||
152 window->HasCapture();
153 });
154 DCHECK(i != windows.cend()) << "Couldn't find RW for " << point.ToString()
155 << " among " << windows.size() << " RWs.";
156 return (*i)->GetRootWindow();
157 }
158
159 ui::X11UIControlsTestHelper x11_ui_controls_test_helper_;
160
161 DISALLOW_COPY_AND_ASSIGN(UIControlsDesktopX11);
162 };
163
164 } // namespace
165
CreateUIControlsDesktopAura()166 UIControlsAura* CreateUIControlsDesktopAura() {
167 return new UIControlsDesktopX11();
168 }
169
170 } // namespace test
171 } // namespace views
172