summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_provider_gtk.cc118
-rw-r--r--chrome/browser/automation/ui_controls_linux.cc50
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.cc25
-rw-r--r--chrome/test/automated_ui_tests/automated_ui_test_base.cc6
-rw-r--r--chrome/test/automated_ui_tests/automated_ui_test_interactive_test.cc10
5 files changed, 177 insertions, 32 deletions
diff --git a/chrome/browser/automation/automation_provider_gtk.cc b/chrome/browser/automation/automation_provider_gtk.cc
index 7036bf3..23e85b9 100644
--- a/chrome/browser/automation/automation_provider_gtk.cc
+++ b/chrome/browser/automation/automation_provider_gtk.cc
@@ -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 @@ void AutomationProvider::GetBookmarkBarVisibility(int handle, bool* visible,
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(provider_);
+ DCHECK(reply_message_);
+ }
+
+ 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) {
diff --git a/chrome/browser/automation/ui_controls_linux.cc b/chrome/browser/automation/ui_controls_linux.cc
index aa18ce2..6b2deee 100644
--- a/chrome/browser/automation/ui_controls_linux.cc
+++ b/chrome/browser/automation/ui_controls_linux.cc
@@ -58,9 +58,9 @@ class EventWaiter : public MessageLoopForUI::Observer {
}
private:
- // We pass ownership of task_ to MessageLoop when the corrent event is
+ // We pass ownership of task_ to MessageLoop when the current event is
// received.
- Task *task_;
+ Task* task_;
GdkEventType type_;
// The number of events of this type to wait for.
int count_;
@@ -87,7 +87,6 @@ class ClickTask : public Task {
Task* followup_;
};
-
bool SendKeyEvent(GdkWindow* window, bool press, guint key, guint state) {
GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
@@ -116,6 +115,35 @@ bool SendKeyEvent(GdkWindow* window, bool press, guint key, guint state) {
return true;
}
+void FakeAMouseMotionEvent(gint x, gint y) {
+ GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
+
+ event->motion.send_event = false;
+ event->motion.time = EventTimeNow();
+
+ GtkWidget* grab_widget = gtk_grab_get_current();
+ if (grab_widget) {
+ // If there is a grab, we need to target all events at it regardless of
+ // what widget the mouse is over.
+ event->motion.window = grab_widget->window;
+ } else {
+ event->motion.window = gdk_window_at_pointer(&x, &y);
+ }
+ g_object_ref(event->motion.window);
+ event->motion.x = x;
+ event->motion.y = y;
+ gint origin_x, origin_y;
+ gdk_window_get_origin(event->motion.window, &origin_x, &origin_y);
+ event->motion.x_root = x + origin_x;
+ event->motion.y_root = y + origin_y;
+
+ event->motion.device = gdk_device_get_core_pointer();
+ event->type = GDK_MOTION_NOTIFY;
+
+ gdk_event_put(event);
+ gdk_event_free(event);
+}
+
} // namespace
namespace ui_controls {
@@ -205,13 +233,18 @@ bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, wchar_t key,
bool SendMouseMove(long x, long y) {
gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(),
x, y);
+ // Sometimes gdk_display_warp_pointer fails to send back any indication of
+ // the move, even though it succesfully moves the server cursor. We fake it in
+ // order to get drags to work.
+ FakeAMouseMotionEvent(x, y);
+
return true;
}
bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
bool rv = SendMouseMove(x, y);
// We can't rely on any particular event signalling the completion of the
- // mouse move. Posting the task to the message loop should gaurantee
+ // mouse move. Posting the task to the message loop hopefully guarantees
// the pointer has moved before task is run (although it may not run it as
// soon as it could).
MessageLoop::current()->PostTask(FROM_HERE, task);
@@ -234,17 +267,18 @@ bool SendMouseEvents(MouseButton type, int state) {
} else {
event->button.window = gdk_window_at_pointer(&x, &y);
}
+
g_object_ref(event->button.window);
- event->motion.x = x;
- event->motion.y = y;
+ event->button.x = x;
+ event->button.y = y;
gint origin_x, origin_y;
gdk_window_get_origin(event->button.window, &origin_x, &origin_y);
event->button.x_root = x + origin_x;
event->button.y_root = y + origin_y;
event->button.axes = NULL;
- // TODO(estade): as above, we may want to pack this with the actual state.
- event->button.state = 0;
+ gdk_window_get_pointer(event->button.window, NULL, NULL,
+ reinterpret_cast<GdkModifierType*>(&event->button.state));
event->button.button = type == LEFT ? 1 : (type == MIDDLE ? 2 : 3);
event->button.device = gdk_device_get_core_pointer();
diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc
index 3850da9..904edc3 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_gtk.cc
@@ -218,24 +218,27 @@ void TabGtk::WillProcessEvent(GdkEvent* event) {
}
void TabGtk::DidProcessEvent(GdkEvent* event) {
- if (event->type != GDK_MOTION_NOTIFY)
+ if (!(event->type == GDK_MOTION_NOTIFY || event->type == GDK_LEAVE_NOTIFY ||
+ event->type == GDK_ENTER_NOTIFY)) {
return;
+ }
if (drag_widget_) {
delegate_->ContinueDrag(NULL);
return;
}
- GdkEventMotion* motion = reinterpret_cast<GdkEventMotion*>(event);
- GdkEventButton* button = reinterpret_cast<GdkEventButton*>(last_mouse_down_);
- bool dragging = gtk_drag_check_threshold(widget(),
- static_cast<gint>(button->x),
- static_cast<gint>(button->y),
- static_cast<gint>(motion->x),
- static_cast<gint>(motion->y));
- if (dragging) {
- StartDragging(gfx::Point(static_cast<int>(button->x),
- static_cast<int>(button->y)));
+ gint old_x = static_cast<gint>(last_mouse_down_->button.x_root);
+ gint old_y = static_cast<gint>(last_mouse_down_->button.y_root);
+ gdouble new_x;
+ gdouble new_y;
+ gdk_event_get_root_coords(event, &new_x, &new_y);
+
+ if (gtk_drag_check_threshold(widget(), old_x, old_y,
+ static_cast<gint>(new_x), static_cast<gint>(new_y))) {
+ StartDragging(gfx::Point(
+ static_cast<int>(last_mouse_down_->button.x),
+ static_cast<int>(last_mouse_down_->button.y)));
}
}
diff --git a/chrome/test/automated_ui_tests/automated_ui_test_base.cc b/chrome/test/automated_ui_tests/automated_ui_test_base.cc
index 81ed10e..9880fd3 100644
--- a/chrome/test/automated_ui_tests/automated_ui_test_base.cc
+++ b/chrome/test/automated_ui_tests/automated_ui_test_base.cc
@@ -17,12 +17,14 @@ AutomatedUITestBase::AutomatedUITestBase() {}
AutomatedUITestBase::~AutomatedUITestBase() {}
-void AutomatedUITestBase::LogErrorMessage(const std::string& error) {}
+void AutomatedUITestBase::LogErrorMessage(const std::string& error) {
+}
void AutomatedUITestBase::LogWarningMessage(const std::string& warning) {
}
-void AutomatedUITestBase::LogInfoMessage(const std::string& info) {}
+void AutomatedUITestBase::LogInfoMessage(const std::string& info) {
+}
void AutomatedUITestBase::SetUp() {
UITest::SetUp();
diff --git a/chrome/test/automated_ui_tests/automated_ui_test_interactive_test.cc b/chrome/test/automated_ui_tests/automated_ui_test_interactive_test.cc
index f7ac5fc..e1d2e64 100644
--- a/chrome/test/automated_ui_tests/automated_ui_test_interactive_test.cc
+++ b/chrome/test/automated_ui_tests/automated_ui_test_interactive_test.cc
@@ -7,12 +7,6 @@
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#if defined(OS_WINDOWS)
-#define MAYBE(x) x
-#else
-#define MAYBE(x) DISABLED_##x
-#endif
-
namespace {
bool WaitForURLDisplayedForTab(BrowserProxy* browser, int tab_index,
@@ -32,7 +26,7 @@ bool WaitForURLDisplayedForTab(BrowserProxy* browser, int tab_index,
} // namespace
-TEST_F(AutomatedUITestBase, MAYBE(DragOut)) {
+TEST_F(AutomatedUITestBase, DragOut) {
int tab_count;
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(1, tab_count);
@@ -54,7 +48,7 @@ TEST_F(AutomatedUITestBase, MAYBE(DragOut)) {
ASSERT_EQ(2, window_count);
}
-TEST_F(AutomatedUITestBase, MAYBE(DragLeftRight)) {
+TEST_F(AutomatedUITestBase, DragLeftRight) {
int tab_count;
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(1, tab_count);