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 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: 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 39 virtual ~WindowDragResponseTask() { 40 } 41 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: 57 MouseEventTask(Task* next_task, ui_controls::MouseButtonState state) 58 : next_task_(next_task), 59 state_(state) {} 60 61 virtual ~MouseEventTask() { 62 } 63 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: 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 88 virtual ~MouseMoveTask() { 89 } 90 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 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