Chromium Code Reviews| Index: chrome/browser/automation/automation_provider_gtk.cc |
| =================================================================== |
| --- chrome/browser/automation/automation_provider_gtk.cc (revision 26890) |
| +++ chrome/browser/automation/automation_provider_gtk.cc (working copy) |
| @@ -4,8 +4,11 @@ |
| #include "chrome/browser/automation/automation_provider.h" |
| +#include <gtk/gtk.h> |
| + |
| #include "base/gfx/point.h" |
| #include "base/gfx/rect.h" |
| +#include "chrome/browser/automation/ui_controls.h" |
| #include "chrome/browser/gtk/browser_window_gtk.h" |
| #include "chrome/browser/gtk/view_id_util.h" |
| #include "chrome/common/gtk_util.h" |
| @@ -94,14 +97,123 @@ |
| NOTIMPLEMENTED(); |
| } |
| +// This task sends a WindowDragResponse message with the appropriate |
| +// routing ID to the automation proxy. This is implemented as a task so that |
| +// we know that the mouse events (and any tasks that they spawn on the message |
| +// loop) have been processed by the time this is sent. |
| +class WindowDragResponseTask : public Task { |
| + public: |
| + WindowDragResponseTask(AutomationProvider* provider, |
| + IPC::Message* reply_message) |
| + : provider_(provider), |
| + reply_message_(reply_message) { |
| + DCHECK(reply_message_); |
| + DCHECK(provider); |
|
Paweł Hajdan Jr.
2009/09/24 18:04:58
very-small-nit: Please be consistent and check thi
|
| + } |
| + |
| + virtual ~WindowDragResponseTask() { |
| + } |
| + |
| + virtual void Run() { |
| + AutomationMsg_WindowDrag::WriteReplyParams(reply_message_, true); |
| + provider_->Send(reply_message_); |
| + } |
| + |
| + private: |
| + AutomationProvider* provider_; |
| + IPC::Message* reply_message_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(WindowDragResponseTask); |
| +}; |
| + |
| +// A task that just runs a SendMouseEvent and performs another task when done. |
| +class MouseEventTask : public Task { |
| + public: |
| + MouseEventTask(Task* next_task, ui_controls::MouseButtonState state) |
| + : next_task_(next_task), |
| + state_(state) {} |
| + |
| + virtual ~MouseEventTask() { |
| + } |
| + |
| + virtual void Run() { |
| + ui_controls::SendMouseEventsNotifyWhenDone(ui_controls::LEFT, state_, |
| + next_task_); |
| + } |
| + |
| + private: |
| + // The task to execute when we are done. |
| + Task* next_task_; |
| + |
| + // Mouse press or mouse release. |
| + ui_controls::MouseButtonState state_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MouseEventTask); |
| +}; |
| + |
| +// A task that just runs a SendMouseMove and performs another task when done. |
| +class MouseMoveTask : public Task { |
| + public: |
| + MouseMoveTask(Task* next_task, int absolute_x, int absolute_y) |
| + : next_task_(next_task), |
| + x_(absolute_x), |
| + y_(absolute_y) { |
| + } |
| + |
| + virtual ~MouseMoveTask() { |
| + } |
| + |
| + virtual void Run() { |
| + ui_controls::SendMouseMoveNotifyWhenDone(x_, y_, next_task_); |
| + } |
| + |
| + private: |
| + // The task to execute when we are done. |
| + Task* next_task_; |
| + |
| + // Coordinates of the press. |
| + int x_; |
| + int y_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MouseMoveTask); |
| +}; |
| + |
| void AutomationProvider::WindowSimulateDrag(int handle, |
| std::vector<gfx::Point> drag_path, |
| int flags, |
| bool press_escape_en_route, |
| IPC::Message* reply_message) { |
| - NOTIMPLEMENTED(); |
| - AutomationMsg_WindowDrag::WriteReplyParams(reply_message, false); |
| - Send(reply_message); |
| + // TODO(estade): don't ignore |flags| or |escape_en_route|. |
| + gfx::NativeWindow window = |
| + browser_tracker_->GetResource(handle)->window()->GetNativeHandle(); |
| + if (window && (drag_path.size() > 1)) { |
| + int x, y; |
| + gdk_window_get_position(GTK_WIDGET(window)->window, &x, &y); |
| + |
| + // Create a nested stack of tasks to run. |
| + Task* next_task = new WindowDragResponseTask(this, reply_message); |
| + next_task = new MouseEventTask(next_task, ui_controls::UP); |
| + next_task = new MouseEventTask(next_task, ui_controls::UP); |
| + for (size_t i = drag_path.size() - 1; i > 0; --i) { |
| + // Smooth out the mouse movements by adding intermediate points. This |
| + // better simulates a real user drag. |
| + int dest_x = drag_path[i].x() + x; |
| + int dest_y = drag_path[i].y() + y; |
| + int half_step_x = (dest_x + drag_path[i - 1].x() + x) / 2; |
| + int half_step_y = (dest_y + drag_path[i - 1].y() + y) / 2; |
| + |
| + next_task = new MouseMoveTask(next_task, dest_x, dest_y); |
| + next_task = new MouseMoveTask(next_task, half_step_x, half_step_y); |
| + } |
| + next_task = new MouseEventTask(next_task, ui_controls::DOWN); |
| + |
| + ui_controls::SendMouseMoveNotifyWhenDone(x + drag_path[0].x(), |
| + y + drag_path[0].y(), |
| + next_task); |
| + } else { |
| + AutomationMsg_WindowDrag::WriteReplyParams(reply_message, false); |
| + Send(reply_message); |
| + } |
| } |
| void AutomationProvider::TerminateSession(int handle, bool* success) { |