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/automation_provider.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/automation/automation_browser_tracker.h"
11 #include "chrome/browser/automation/automation_window_tracker.h"
12 #include "chrome/browser/automation/ui_controls.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
15 #include "chrome/browser/ui/gtk/gtk_util.h"
16 #include "chrome/browser/ui/gtk/view_id_util.h"
17 #include "chrome/common/automation_messages.h"
18 #include "ui/gfx/point.h"
19 #include "ui/gfx/rect.h"
20
PrintAsync(int tab_handle)21 void AutomationProvider::PrintAsync(int tab_handle) {
22 NOTIMPLEMENTED();
23 }
24
25 // This task sends a WindowDragResponse message with the appropriate
26 // routing ID to the automation proxy. This is implemented as a task so that
27 // we know that the mouse events (and any tasks that they spawn on the message
28 // loop) have been processed by the time this is sent.
29 class WindowDragResponseTask : public Task {
30 public:
WindowDragResponseTask(AutomationProvider * provider,IPC::Message * reply_message)31 WindowDragResponseTask(AutomationProvider* provider,
32 IPC::Message* reply_message)
33 : provider_(provider),
34 reply_message_(reply_message) {
35 DCHECK(provider_);
36 DCHECK(reply_message_);
37 }
38
~WindowDragResponseTask()39 virtual ~WindowDragResponseTask() {
40 }
41
Run()42 virtual void Run() {
43 AutomationMsg_WindowDrag::WriteReplyParams(reply_message_, true);
44 provider_->Send(reply_message_);
45 }
46
47 private:
48 AutomationProvider* provider_;
49 IPC::Message* reply_message_;
50
51 DISALLOW_COPY_AND_ASSIGN(WindowDragResponseTask);
52 };
53
54 // A task that just runs a SendMouseEvent and performs another task when done.
55 class MouseEventTask : public Task {
56 public:
MouseEventTask(Task * next_task,ui_controls::MouseButtonState state)57 MouseEventTask(Task* next_task, ui_controls::MouseButtonState state)
58 : next_task_(next_task),
59 state_(state) {}
60
~MouseEventTask()61 virtual ~MouseEventTask() {
62 }
63
Run()64 virtual void Run() {
65 ui_controls::SendMouseEventsNotifyWhenDone(ui_controls::LEFT, state_,
66 next_task_);
67 }
68
69 private:
70 // The task to execute when we are done.
71 Task* next_task_;
72
73 // Mouse press or mouse release.
74 ui_controls::MouseButtonState state_;
75
76 DISALLOW_COPY_AND_ASSIGN(MouseEventTask);
77 };
78
79 // A task that just runs a SendMouseMove and performs another task when done.
80 class MouseMoveTask : public Task {
81 public:
MouseMoveTask(Task * next_task,int absolute_x,int absolute_y)82 MouseMoveTask(Task* next_task, int absolute_x, int absolute_y)
83 : next_task_(next_task),
84 x_(absolute_x),
85 y_(absolute_y) {
86 }
87
~MouseMoveTask()88 virtual ~MouseMoveTask() {
89 }
90
Run()91 virtual void Run() {
92 ui_controls::SendMouseMoveNotifyWhenDone(x_, y_, next_task_);
93 }
94
95 private:
96 // The task to execute when we are done.
97 Task* next_task_;
98
99 // Coordinates of the press.
100 int x_;
101 int y_;
102
103 DISALLOW_COPY_AND_ASSIGN(MouseMoveTask);
104 };
105
WindowSimulateDrag(int handle,const std::vector<gfx::Point> & drag_path,int flags,bool press_escape_en_route,IPC::Message * reply_message)106 void AutomationProvider::WindowSimulateDrag(
107 int handle,
108 const std::vector<gfx::Point>& drag_path,
109 int flags,
110 bool press_escape_en_route,
111 IPC::Message* reply_message) {
112 // TODO(estade): don't ignore |flags| or |escape_en_route|.
113 gfx::NativeWindow window =
114 browser_tracker_->GetResource(handle)->window()->GetNativeHandle();
115 if (window && (drag_path.size() > 1)) {
116 int x, y;
117 gdk_window_get_position(GTK_WIDGET(window)->window, &x, &y);
118
119 // Create a nested stack of tasks to run.
120 Task* next_task = new WindowDragResponseTask(this, reply_message);
121 next_task = new MouseEventTask(next_task, ui_controls::UP);
122 next_task = new MouseEventTask(next_task, ui_controls::UP);
123 for (size_t i = drag_path.size() - 1; i > 0; --i) {
124 // Smooth out the mouse movements by adding intermediate points. This
125 // better simulates a real user drag.
126 int dest_x = drag_path[i].x() + x;
127 int dest_y = drag_path[i].y() + y;
128 int half_step_x = (dest_x + drag_path[i - 1].x() + x) / 2;
129 int half_step_y = (dest_y + drag_path[i - 1].y() + y) / 2;
130
131 next_task = new MouseMoveTask(next_task, dest_x, dest_y);
132 next_task = new MouseMoveTask(next_task, half_step_x, half_step_y);
133 }
134 next_task = new MouseEventTask(next_task, ui_controls::DOWN);
135
136 ui_controls::SendMouseMoveNotifyWhenDone(x + drag_path[0].x(),
137 y + drag_path[0].y(),
138 next_task);
139 } else {
140 AutomationMsg_WindowDrag::WriteReplyParams(reply_message, false);
141 Send(reply_message);
142 }
143 }
144