| Index: chrome/test/base/interactive_test_utils_mac.mm
|
| diff --git a/chrome/test/base/interactive_test_utils_mac.mm b/chrome/test/base/interactive_test_utils_mac.mm
|
| index 0d00f3a6614e3aacd4c9141ed971ae02590ea1d1..8fc11a02d189941f6fecf88d4ed549a342121c9a 100644
|
| --- a/chrome/test/base/interactive_test_utils_mac.mm
|
| +++ b/chrome/test/base/interactive_test_utils_mac.mm
|
| @@ -9,7 +9,135 @@
|
|
|
| #include "base/message_loop/message_loop.h"
|
| #include "chrome/app/chrome_command_ids.h"
|
| +#include "chrome/browser/ui/views/tabs/window_finder.h"
|
| +#include "content/public/test/test_utils.h"
|
| #import "ui/base/test/windowed_nsnotification_observer.h"
|
| +#include "ui/gfx/animation/tween.h"
|
| +#include "ui/gfx/mac/coordinate_conversion.h"
|
| +#include "ui/views/cocoa/bridged_native_widget.h"
|
| +#include "ui/views/event_monitor.h"
|
| +#include "ui/views/widget/native_widget_mac.h"
|
| +
|
| +namespace {
|
| +
|
| +bool WaitForEvent(
|
| + bool (^dispatch_event_block)(const base::Closure& quit_closure)) {
|
| + scoped_refptr<content::MessageLoopRunner> runner =
|
| + new content::MessageLoopRunner;
|
| + bool result = dispatch_event_block(runner->QuitClosure());
|
| + runner->Run();
|
| + return result;
|
| +}
|
| +
|
| +bool MouseMove(const gfx::Point& p) {
|
| + return WaitForEvent(^(const base::Closure& quit_closure) {
|
| + return ui_controls::SendMouseMoveNotifyWhenDone(p.x(), p.y(), quit_closure);
|
| + });
|
| +}
|
| +
|
| +bool MouseDown() {
|
| + return WaitForEvent(^(const base::Closure& quit_closure) {
|
| + return ui_controls::SendMouseEventsNotifyWhenDone(
|
| + ui_controls::LEFT, ui_controls::DOWN, quit_closure);
|
| + });
|
| +}
|
| +
|
| +bool MouseUp() {
|
| + return WaitForEvent(^(const base::Closure& quit_closure) {
|
| + return ui_controls::SendMouseEventsNotifyWhenDone(
|
| + ui_controls::LEFT, ui_controls::UP, quit_closure);
|
| + });
|
| +}
|
| +
|
| +class ScopedCGEventsEnabler {
|
| + public:
|
| + ScopedCGEventsEnabler()
|
| + : enable_cgevents_(ui_controls::SendMouseEventsAsCGEvents()) {
|
| + ui_controls::SetSendMouseEventsAsCGEvents(true);
|
| + }
|
| +
|
| + ~ScopedCGEventsEnabler() {
|
| + ui_controls::SetSendMouseEventsAsCGEvents(enable_cgevents_);
|
| + }
|
| +
|
| + private:
|
| + bool enable_cgevents_;
|
| +};
|
| +
|
| +void RunAtBackgroundQueue(void (^block)()) {
|
| + auto queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
| + scoped_refptr<content::MessageLoopRunner> runner =
|
| + new content::MessageLoopRunner;
|
| +
|
| + dispatch_async(queue, ^{
|
| + scoped_ptr<base::MessageLoop> loop(
|
| + new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
|
| +
|
| + block();
|
| +
|
| + dispatch_async(dispatch_get_main_queue(), ^{
|
| + runner->Quit();
|
| + });
|
| + });
|
| +
|
| + // We need to run the loop on the main thread, so the mouse events will be
|
| + // actually processed.
|
| + runner->Run();
|
| +}
|
| +
|
| +bool WindowIsMoving(NSWindow* window) {
|
| + views::BridgedNativeWidget* bridge =
|
| + views::NativeWidgetMac::GetBridgeForNativeWindow(window);
|
| + DCHECK(bridge);
|
| + return bridge->IsRunMoveLoopActive();
|
| +}
|
| +
|
| +// If current window under the cursor is currently moving by WindowServer, wait
|
| +// for the NSWindowMovedEventType notification.
|
| +//
|
| +// Returns whether the window under the cursor was moved by the system.
|
| +bool WaitForSystemWindowMoveToStop() {
|
| + // NOTE: This is a potentially troublesome part, currently it only works
|
| + // with MacViewsBrowser when the moved window entered RunMoveLoop.
|
| + // On non-MacViewsBrowser builds or when the window was moved using the
|
| + // caption we would be unable to detect that the window was moved using the
|
| + // WindowServer and would not wait for the final NSWindowMovedEventType
|
| + // notification.
|
| + //
|
| + // As a possible solution it would be possible to add an
|
| + // additional argument to the function
|
| + // |force_wait_for_system_window_move_to_finish|, and force waiting for
|
| + // notification if this ever becomes a problem.
|
| + NSWindow* window =
|
| + GetLocalProcessWindowAtPoint(views::EventMonitor::GetLastMouseLocation(),
|
| + std::set<gfx::NativeWindow>());
|
| + const bool window_is_moving_by_system = window && WindowIsMoving(window);
|
| +
|
| + if (window_is_moving_by_system) {
|
| + // Wait for a final NSWindowMovedEventType notification, otherwise
|
| + // the window won't be in the final position. It arrives asynchronously
|
| + // after the mouse move events.
|
| + NSEvent* window_move_event =
|
| + [NSEvent otherEventWithType:NSAppKitDefined
|
| + location:NSZeroPoint
|
| + modifierFlags:0
|
| + timestamp:0
|
| + windowNumber:0
|
| + context:0
|
| + subtype:NSWindowMovedEventType
|
| + data1:0
|
| + data2:0];
|
| + scoped_refptr<content::MessageLoopRunner> no_window_move_runner =
|
| + new content::MessageLoopRunner;
|
| + ui_controls::NotifyWhenEventIsProcessed(
|
| + window_move_event, no_window_move_runner->QuitClosure());
|
| + no_window_move_runner->Run();
|
| + }
|
| +
|
| + return window_is_moving_by_system;
|
| +}
|
| +
|
| +} // namespace
|
|
|
| namespace ui_test_utils {
|
|
|
| @@ -44,4 +172,35 @@ bool ShowAndFocusNativeWindow(gfx::NativeWindow window) {
|
| return !async_waiter || notification_observed;
|
| }
|
|
|
| +void DragAndDrop(const gfx::Point& from,
|
| + const gfx::Point& to,
|
| + int steps) {
|
| + DCHECK_GE(steps, 1);
|
| +
|
| + ScopedCGEventsEnabler cgevents_enabler;
|
| +
|
| + RunAtBackgroundQueue(^() {
|
| + MouseMove(from);
|
| + MouseDown();
|
| +
|
| + // If steps is greater than 1, then we need to use CGEvents, otherwise
|
| + // the CocoaWindowMoveLoop won't actually work, as the window dragging works
|
| + // on the WindowServer level.
|
| + for (int i = 1; i <= steps; ++i) {
|
| + const double progress = static_cast<double>(i) / steps;
|
| + const gfx::Point p(
|
| + gfx::Tween::IntValueBetween(progress, from.x(), to.x()),
|
| + gfx::Tween::IntValueBetween(progress, from.y(), to.y()));
|
| + MouseMove(p);
|
| + }
|
| +
|
| + const bool window_was_moved_by_system = WaitForSystemWindowMoveToStop();
|
| + if (steps > 1) {
|
| + ASSERT_TRUE(window_was_moved_by_system);
|
| + }
|
| +
|
| + MouseUp();
|
| + });
|
| +}
|
| +
|
| } // namespace ui_test_utils
|
|
|