OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/automation/ui_controls.h" | 5 #include "chrome/browser/automation/ui_controls.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 #include <gdk/gdkkeysyms.h> | 8 #include <gdk/gdkkeysyms.h> |
9 | 9 |
10 #include "base/gfx/rect.h" | 10 #include "base/gfx/rect.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 MessageLoop::current()->PostTask(FROM_HERE, task_); | 51 MessageLoop::current()->PostTask(FROM_HERE, task_); |
52 delete this; | 52 delete this; |
53 } | 53 } |
54 } | 54 } |
55 | 55 |
56 virtual void DidProcessEvent(GdkEvent* event) { | 56 virtual void DidProcessEvent(GdkEvent* event) { |
57 // No-op. | 57 // No-op. |
58 } | 58 } |
59 | 59 |
60 private: | 60 private: |
61 // We pass ownership of task_ to MessageLoop when the corrent event is | 61 // We pass ownership of task_ to MessageLoop when the current event is |
62 // received. | 62 // received. |
63 Task *task_; | 63 Task* task_; |
64 GdkEventType type_; | 64 GdkEventType type_; |
65 // The number of events of this type to wait for. | 65 // The number of events of this type to wait for. |
66 int count_; | 66 int count_; |
67 }; | 67 }; |
68 | 68 |
69 class ClickTask : public Task { | 69 class ClickTask : public Task { |
70 public: | 70 public: |
71 ClickTask(ui_controls::MouseButton button, int state, Task* followup) | 71 ClickTask(ui_controls::MouseButton button, int state, Task* followup) |
72 : button_(button), state_(state), followup_(followup) { | 72 : button_(button), state_(state), followup_(followup) { |
73 } | 73 } |
74 | 74 |
75 virtual ~ClickTask() {} | 75 virtual ~ClickTask() {} |
76 | 76 |
77 virtual void Run() { | 77 virtual void Run() { |
78 if (followup_) | 78 if (followup_) |
79 ui_controls::SendMouseEventsNotifyWhenDone(button_, state_, followup_); | 79 ui_controls::SendMouseEventsNotifyWhenDone(button_, state_, followup_); |
80 else | 80 else |
81 ui_controls::SendMouseEvents(button_, state_); | 81 ui_controls::SendMouseEvents(button_, state_); |
82 } | 82 } |
83 | 83 |
84 private: | 84 private: |
85 ui_controls::MouseButton button_; | 85 ui_controls::MouseButton button_; |
86 int state_; | 86 int state_; |
87 Task* followup_; | 87 Task* followup_; |
88 }; | 88 }; |
89 | 89 |
90 | |
91 bool SendKeyEvent(GdkWindow* window, bool press, guint key, guint state) { | 90 bool SendKeyEvent(GdkWindow* window, bool press, guint key, guint state) { |
92 GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE); | 91 GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE); |
93 | 92 |
94 event->key.type = press ? GDK_KEY_PRESS : GDK_KEY_RELEASE; | 93 event->key.type = press ? GDK_KEY_PRESS : GDK_KEY_RELEASE; |
95 event->key.window = window; | 94 event->key.window = window; |
96 g_object_ref(event->key.window); | 95 g_object_ref(event->key.window); |
97 event->key.send_event = false; | 96 event->key.send_event = false; |
98 event->key.time = EventTimeNow(); | 97 event->key.time = EventTimeNow(); |
99 | 98 |
100 event->key.state = state; | 99 event->key.state = state; |
101 event->key.keyval = key; | 100 event->key.keyval = key; |
102 | 101 |
103 GdkKeymapKey* keys; | 102 GdkKeymapKey* keys; |
104 gint n_keys; | 103 gint n_keys; |
105 if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), | 104 if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), |
106 event->key.keyval, &keys, &n_keys)) { | 105 event->key.keyval, &keys, &n_keys)) { |
107 return false; | 106 return false; |
108 } | 107 } |
109 event->key.hardware_keycode = keys[0].keycode; | 108 event->key.hardware_keycode = keys[0].keycode; |
110 event->key.group = keys[0].group; | 109 event->key.group = keys[0].group; |
111 g_free(keys); | 110 g_free(keys); |
112 | 111 |
113 gdk_event_put(event); | 112 gdk_event_put(event); |
114 // gdk_event_put appends a copy of the event. | 113 // gdk_event_put appends a copy of the event. |
115 gdk_event_free(event); | 114 gdk_event_free(event); |
116 return true; | 115 return true; |
117 } | 116 } |
118 | 117 |
| 118 void FakeAMouseMotionEvent(gint x, gint y) { |
| 119 GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY); |
| 120 |
| 121 event->motion.send_event = false; |
| 122 event->motion.time = EventTimeNow(); |
| 123 |
| 124 GtkWidget* grab_widget = gtk_grab_get_current(); |
| 125 if (grab_widget) { |
| 126 // If there is a grab, we need to target all events at it regardless of |
| 127 // what widget the mouse is over. |
| 128 event->motion.window = grab_widget->window; |
| 129 } else { |
| 130 event->motion.window = gdk_window_at_pointer(&x, &y); |
| 131 } |
| 132 g_object_ref(event->motion.window); |
| 133 event->motion.x = x; |
| 134 event->motion.y = y; |
| 135 gint origin_x, origin_y; |
| 136 gdk_window_get_origin(event->motion.window, &origin_x, &origin_y); |
| 137 event->motion.x_root = x + origin_x; |
| 138 event->motion.y_root = y + origin_y; |
| 139 |
| 140 event->motion.device = gdk_device_get_core_pointer(); |
| 141 event->type = GDK_MOTION_NOTIFY; |
| 142 |
| 143 gdk_event_put(event); |
| 144 gdk_event_free(event); |
| 145 } |
| 146 |
119 } // namespace | 147 } // namespace |
120 | 148 |
121 namespace ui_controls { | 149 namespace ui_controls { |
122 | 150 |
123 bool SendKeyPress(gfx::NativeWindow window, | 151 bool SendKeyPress(gfx::NativeWindow window, |
124 wchar_t key, bool control, bool shift, bool alt) { | 152 wchar_t key, bool control, bool shift, bool alt) { |
125 GdkWindow* event_window = NULL; | 153 GdkWindow* event_window = NULL; |
126 GtkWidget* grab_widget = gtk_grab_get_current(); | 154 GtkWidget* grab_widget = gtk_grab_get_current(); |
127 if (grab_widget) { | 155 if (grab_widget) { |
128 // If there is a grab, send all events to the grabbed widget. | 156 // If there is a grab, send all events to the grabbed widget. |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 if (alt) | 226 if (alt) |
199 release_count++; | 227 release_count++; |
200 // This object will delete itself after running |task|. | 228 // This object will delete itself after running |task|. |
201 new EventWaiter(task, GDK_KEY_RELEASE, release_count); | 229 new EventWaiter(task, GDK_KEY_RELEASE, release_count); |
202 return SendKeyPress(window, key, control, shift, alt); | 230 return SendKeyPress(window, key, control, shift, alt); |
203 } | 231 } |
204 | 232 |
205 bool SendMouseMove(long x, long y) { | 233 bool SendMouseMove(long x, long y) { |
206 gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(), | 234 gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(), |
207 x, y); | 235 x, y); |
| 236 // Sometimes gdk_display_warp_pointer fails to send back any indication of |
| 237 // the move, even though it succesfully moves the server cursor. We fake it in |
| 238 // order to get drags to work. |
| 239 FakeAMouseMotionEvent(x, y); |
| 240 |
208 return true; | 241 return true; |
209 } | 242 } |
210 | 243 |
211 bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) { | 244 bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) { |
212 bool rv = SendMouseMove(x, y); | 245 bool rv = SendMouseMove(x, y); |
213 // We can't rely on any particular event signalling the completion of the | 246 // We can't rely on any particular event signalling the completion of the |
214 // mouse move. Posting the task to the message loop should gaurantee | 247 // mouse move. Posting the task to the message loop hopefully guarantees |
215 // the pointer has moved before task is run (although it may not run it as | 248 // the pointer has moved before task is run (although it may not run it as |
216 // soon as it could). | 249 // soon as it could). |
217 MessageLoop::current()->PostTask(FROM_HERE, task); | 250 MessageLoop::current()->PostTask(FROM_HERE, task); |
218 return rv; | 251 return rv; |
219 } | 252 } |
220 | 253 |
221 bool SendMouseEvents(MouseButton type, int state) { | 254 bool SendMouseEvents(MouseButton type, int state) { |
222 GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS); | 255 GdkEvent* event = gdk_event_new(GDK_BUTTON_PRESS); |
223 | 256 |
224 event->button.send_event = false; | 257 event->button.send_event = false; |
225 event->button.time = EventTimeNow(); | 258 event->button.time = EventTimeNow(); |
226 | 259 |
227 gint x, y; | 260 gint x, y; |
228 GtkWidget* grab_widget = gtk_grab_get_current(); | 261 GtkWidget* grab_widget = gtk_grab_get_current(); |
229 if (grab_widget) { | 262 if (grab_widget) { |
230 // If there is a grab, we need to target all events at it regardless of | 263 // If there is a grab, we need to target all events at it regardless of |
231 // what widget the mouse is over. | 264 // what widget the mouse is over. |
232 event->button.window = grab_widget->window; | 265 event->button.window = grab_widget->window; |
233 gdk_window_get_pointer(event->button.window, &x, &y, NULL); | 266 gdk_window_get_pointer(event->button.window, &x, &y, NULL); |
234 } else { | 267 } else { |
235 event->button.window = gdk_window_at_pointer(&x, &y); | 268 event->button.window = gdk_window_at_pointer(&x, &y); |
236 } | 269 } |
| 270 |
237 g_object_ref(event->button.window); | 271 g_object_ref(event->button.window); |
238 event->motion.x = x; | 272 event->button.x = x; |
239 event->motion.y = y; | 273 event->button.y = y; |
240 gint origin_x, origin_y; | 274 gint origin_x, origin_y; |
241 gdk_window_get_origin(event->button.window, &origin_x, &origin_y); | 275 gdk_window_get_origin(event->button.window, &origin_x, &origin_y); |
242 event->button.x_root = x + origin_x; | 276 event->button.x_root = x + origin_x; |
243 event->button.y_root = y + origin_y; | 277 event->button.y_root = y + origin_y; |
244 | 278 |
245 event->button.axes = NULL; | 279 event->button.axes = NULL; |
246 // TODO(estade): as above, we may want to pack this with the actual state. | 280 gdk_window_get_pointer(event->button.window, NULL, NULL, |
247 event->button.state = 0; | 281 reinterpret_cast<GdkModifierType*>(&event->button.state)); |
248 event->button.button = type == LEFT ? 1 : (type == MIDDLE ? 2 : 3); | 282 event->button.button = type == LEFT ? 1 : (type == MIDDLE ? 2 : 3); |
249 event->button.device = gdk_device_get_core_pointer(); | 283 event->button.device = gdk_device_get_core_pointer(); |
250 | 284 |
251 event->button.type = GDK_BUTTON_PRESS; | 285 event->button.type = GDK_BUTTON_PRESS; |
252 if (state & DOWN) | 286 if (state & DOWN) |
253 gdk_event_put(event); | 287 gdk_event_put(event); |
254 | 288 |
255 // Also send a release event. | 289 // Also send a release event. |
256 GdkEvent* release_event = gdk_event_copy(event); | 290 GdkEvent* release_event = gdk_event_copy(event); |
257 release_event->button.type = GDK_BUTTON_RELEASE; | 291 release_event->button.type = GDK_BUTTON_RELEASE; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 int state, | 334 int state, |
301 Task* task) { | 335 Task* task) { |
302 gfx::Rect bounds = gtk_util::GetWidgetScreenBounds(widget); | 336 gfx::Rect bounds = gtk_util::GetWidgetScreenBounds(widget); |
303 SendMouseMoveNotifyWhenDone(bounds.x() + bounds.width() / 2, | 337 SendMouseMoveNotifyWhenDone(bounds.x() + bounds.width() / 2, |
304 bounds.y() + bounds.height() / 2, | 338 bounds.y() + bounds.height() / 2, |
305 new ClickTask(button, state, task)); | 339 new ClickTask(button, state, task)); |
306 } | 340 } |
307 #endif | 341 #endif |
308 | 342 |
309 } // namespace ui_controls | 343 } // namespace ui_controls |
OLD | NEW |