Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: chrome/browser/automation/ui_controls_gtk.cc

Issue 9390038: Move automation/ui_controls to ui/ui_controls (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: win_aura fix, sync Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/automation/ui_controls.h"
6
7 #include <gdk/gdkkeysyms.h>
8 #include <gtk/gtk.h>
9
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/message_loop.h"
13 #include "chrome/browser/automation/ui_controls_internal.h"
14 #include "chrome/browser/ui/gtk/gtk_util.h"
15 #include "chrome/common/automation_constants.h"
16 #include "ui/base/gtk/event_synthesis_gtk.h"
17 #include "ui/gfx/rect.h"
18
19 #if defined(TOOLKIT_VIEWS)
20 #include "ui/views/view.h"
21 #include "ui/views/widget/widget.h"
22 #endif
23
24 namespace {
25
26 // static
27 guint32 XTimeNow() {
28 struct timespec ts;
29 clock_gettime(CLOCK_MONOTONIC, &ts);
30 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
31 }
32
33 class EventWaiter : public MessageLoopForUI::Observer {
34 public:
35 EventWaiter(const base::Closure& task, GdkEventType type, int count)
36 : task_(task),
37 type_(type),
38 count_(count) {
39 MessageLoopForUI::current()->AddObserver(this);
40 }
41
42 virtual ~EventWaiter() {
43 MessageLoopForUI::current()->RemoveObserver(this);
44 }
45
46 // MessageLoop::Observer implementation:
47 virtual void WillProcessEvent(GdkEvent* event) OVERRIDE {
48 if ((event->type == type_) && (--count_ == 0)) {
49 // At the time we're invoked the event has not actually been processed.
50 // Use PostTask to make sure the event has been processed before
51 // notifying.
52 // NOTE: if processing a message results in running a nested message
53 // loop, then DidProcessEvent isn't immediately sent. As such, we do
54 // the processing in WillProcessEvent rather than DidProcessEvent.
55 MessageLoop::current()->PostTask(FROM_HERE, task_);
56 delete this;
57 }
58 }
59
60 virtual void DidProcessEvent(GdkEvent* event) OVERRIDE {
61 // No-op.
62 }
63
64 private:
65 base::Closure task_;
66 GdkEventType type_;
67 // The number of events of this type to wait for.
68 int count_;
69 };
70
71 void FakeAMouseMotionEvent(gint x, gint y) {
72 GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
73
74 event->motion.send_event = false;
75 event->motion.time = XTimeNow();
76
77 GtkWidget* grab_widget = gtk_grab_get_current();
78 if (grab_widget) {
79 // If there is a grab, we need to target all events at it regardless of
80 // what widget the mouse is over.
81 event->motion.window = gtk_widget_get_window(grab_widget);
82 } else {
83 event->motion.window = gdk_window_at_pointer(&x, &y);
84 }
85 g_object_ref(event->motion.window);
86 gint window_x, window_y;
87 gdk_window_get_origin(event->motion.window, &window_x, &window_y);
88 event->motion.x = x - window_x;
89 event->motion.y = y - window_y;
90 event->motion.x_root = x;
91 event->motion.y_root = y;
92
93 event->motion.device = gdk_device_get_core_pointer();
94 event->type = GDK_MOTION_NOTIFY;
95
96 gdk_event_put(event);
97 gdk_event_free(event);
98 }
99
100 } // namespace
101
102 namespace ui_controls {
103
104 bool SendKeyPress(gfx::NativeWindow window,
105 ui::KeyboardCode key,
106 bool control,
107 bool shift,
108 bool alt,
109 bool command) {
110 DCHECK(!command); // No command key on Linux
111 GdkWindow* event_window = NULL;
112 GtkWidget* grab_widget = gtk_grab_get_current();
113 if (grab_widget) {
114 // If there is a grab, send all events to the grabbed widget.
115 event_window = gtk_widget_get_window(grab_widget);
116 } else if (window) {
117 event_window = gtk_widget_get_window(GTK_WIDGET(window));
118 } else {
119 // No target was specified. Send the events to the active toplevel.
120 GList* windows = gtk_window_list_toplevels();
121 for (GList* element = windows; element; element = g_list_next(element)) {
122 GtkWindow* this_window = GTK_WINDOW(element->data);
123 if (gtk_window_is_active(this_window)) {
124 event_window = gtk_widget_get_window(GTK_WIDGET(this_window));
125 break;
126 }
127 }
128 g_list_free(windows);
129 }
130 if (!event_window) {
131 NOTREACHED() << "Window not specified and none is active";
132 return false;
133 }
134
135 std::vector<GdkEvent*> events;
136 ui::SynthesizeKeyPressEvents(event_window, key, control, shift, alt, &events);
137 for (std::vector<GdkEvent*>::iterator iter = events.begin();
138 iter != events.end(); ++iter) {
139 gdk_event_put(*iter);
140 // gdk_event_put appends a copy of the event.
141 gdk_event_free(*iter);
142 }
143
144 return true;
145 }
146
147 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
148 ui::KeyboardCode key,
149 bool control,
150 bool shift,
151 bool alt,
152 bool command,
153 const base::Closure& task) {
154 DCHECK(!command); // No command key on Linux
155 int release_count = 1;
156 if (control)
157 release_count++;
158 if (shift)
159 release_count++;
160 if (alt)
161 release_count++;
162 // This object will delete itself after running |task|.
163 new EventWaiter(task, GDK_KEY_RELEASE, release_count);
164 return SendKeyPress(window, key, control, shift, alt, command);
165 }
166
167 bool SendMouseMove(long x, long y) {
168 gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(),
169 x, y);
170 // Sometimes gdk_display_warp_pointer fails to send back any indication of
171 // the move, even though it succesfully moves the server cursor. We fake it in
172 // order to get drags to work.
173 FakeAMouseMotionEvent(x, y);
174 return true;
175 }
176
177 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
178 bool rv = SendMouseMove(x, y);
179 new EventWaiter(task, GDK_MOTION_NOTIFY, 1);
180 return rv;
181 }
182
183 bool SendMouseEvents(MouseButton type, int state) {
184 GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS);
185
186 event->button.send_event = false;
187 event->button.time = XTimeNow();
188
189 gint x, y;
190 GtkWidget* grab_widget = gtk_grab_get_current();
191 if (grab_widget) {
192 // If there is a grab, we need to target all events at it regardless of
193 // what widget the mouse is over.
194 event->button.window = gtk_widget_get_window(grab_widget);
195 gdk_window_get_pointer(event->button.window, &x, &y, NULL);
196 } else {
197 event->button.window = gdk_window_at_pointer(&x, &y);
198 CHECK(event->button.window);
199 }
200
201 g_object_ref(event->button.window);
202 event->button.x = x;
203 event->button.y = y;
204 gint origin_x, origin_y;
205 gdk_window_get_origin(event->button.window, &origin_x, &origin_y);
206 event->button.x_root = x + origin_x;
207 event->button.y_root = y + origin_y;
208
209 event->button.axes = NULL;
210 GdkModifierType modifier;
211 gdk_window_get_pointer(event->button.window, NULL, NULL, &modifier);
212 event->button.state = modifier;
213 event->button.button = type == LEFT ? 1 : (type == MIDDLE ? 2 : 3);
214 event->button.device = gdk_device_get_core_pointer();
215
216 event->button.type = GDK_BUTTON_PRESS;
217 if (state & DOWN)
218 gdk_event_put(event);
219
220 // Also send a release event.
221 GdkEvent* release_event = gdk_event_copy(event);
222 release_event->button.type = GDK_BUTTON_RELEASE;
223 release_event->button.time++;
224 if (state & UP)
225 gdk_event_put(release_event);
226
227 gdk_event_free(event);
228 gdk_event_free(release_event);
229
230 return false;
231 }
232
233 bool SendMouseEventsNotifyWhenDone(MouseButton type,
234 int state,
235 const base::Closure& task) {
236 bool rv = SendMouseEvents(type, state);
237 GdkEventType wait_type;
238 if (state & UP) {
239 wait_type = GDK_BUTTON_RELEASE;
240 } else {
241 if (type == LEFT)
242 wait_type = GDK_BUTTON_PRESS;
243 else if (type == MIDDLE)
244 wait_type = GDK_2BUTTON_PRESS;
245 else
246 wait_type = GDK_3BUTTON_PRESS;
247 }
248 new EventWaiter(task, wait_type, 1);
249 return rv;
250 }
251
252 bool SendMouseClick(MouseButton type) {
253 return SendMouseEvents(type, UP | DOWN);
254 }
255
256 #if defined(TOOLKIT_VIEWS)
257
258 #if defined(OS_LINUX) && !defined(USE_AURA)
259 void OnConfigure(GtkWidget* gtk_widget, GdkEvent* event, gpointer data) {
260 views::Widget* widget = static_cast<views::Widget*>(data);
261 gfx::Rect actual = widget->GetWindowScreenBounds();
262 gfx::Rect desired = widget->GetRootView()->bounds();
263 if (actual.size() == desired.size())
264 MessageLoop::current()->Quit();
265 }
266
267 void SynchronizeWidgetSize(views::Widget* widget) {
268 // If the actual window size and desired window size
269 // are different, wait until the window is resized
270 // to desired size.
271 gfx::Rect actual = widget->GetWindowScreenBounds();
272 gfx::Rect desired = widget->GetRootView()->bounds();
273 if (actual.size() != desired.size()) {
274 // Listen to configure-event that is emitted when an window gets
275 // resized.
276 GtkWidget* gtk_widget = widget->GetNativeView();
277 g_signal_connect(gtk_widget, "configure-event",
278 G_CALLBACK(&OnConfigure), widget);
279 MessageLoop::current()->Run();
280 }
281 }
282 #endif
283
284 void MoveMouseToCenterAndPress(views::View* view,
285 MouseButton button,
286 int state,
287 const base::Closure& task) {
288 #if defined(OS_LINUX)
289 // X is asynchronous and we need to wait until the window gets
290 // resized to desired size.
291 SynchronizeWidgetSize(view->GetWidget());
292 #endif
293
294 gfx::Point view_center(view->width() / 2, view->height() / 2);
295 views::View::ConvertPointToScreen(view, &view_center);
296 SendMouseMoveNotifyWhenDone(
297 view_center.x(), view_center.y(),
298 base::Bind(&ui_controls::internal::ClickTask, button, state, task));
299 }
300 #else
301 void MoveMouseToCenterAndPress(GtkWidget* widget,
302 MouseButton button,
303 int state,
304 const base::Closure& task) {
305 gfx::Rect bounds = gtk_util::GetWidgetScreenBounds(widget);
306 SendMouseMoveNotifyWhenDone(
307 bounds.x() + bounds.width() / 2,
308 bounds.y() + bounds.height() / 2,
309 base::Bind(&ui_controls::internal::ClickTask, button, state, task));
310 }
311 #endif
312
313 #if defined(TOOLKIT_VIEWS)
314 void RunClosureAfterAllPendingUIEvents(const base::Closure& task) {
315 // Send noop event and run task.
316 int x, y;
317 gdk_window_at_pointer(&x, &y);
318 SendMouseMoveNotifyWhenDone(x, y, task);
319 }
320 #endif
321
322 } // namespace ui_controls
OLDNEW
« no previous file with comments | « chrome/browser/automation/ui_controls_aurax11.cc ('k') | chrome/browser/automation/ui_controls_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698