Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: chrome/test/base/interactive_test_utils_mac.mm

Issue 1747803003: MacViews: Implement Tab Dragging (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Extract CocoaWindowMoveLoop, fix review issues. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/test/base/interactive_test_utils.h" 5 #include "chrome/test/base/interactive_test_utils.h"
6 6
7 #include <Carbon/Carbon.h> 7 #include <Carbon/Carbon.h>
8 #import <Cocoa/Cocoa.h> 8 #import <Cocoa/Cocoa.h>
9 9
10 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
11 #include "chrome/app/chrome_command_ids.h" 11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/ui/views/tabs/window_finder.h"
13 #include "content/public/test/test_utils.h"
12 #import "ui/base/test/windowed_nsnotification_observer.h" 14 #import "ui/base/test/windowed_nsnotification_observer.h"
15 #include "ui/gfx/animation/tween.h"
16 #include "ui/gfx/mac/coordinate_conversion.h"
17 #include "ui/views/cocoa/bridged_native_widget.h"
18 #include "ui/views/event_monitor.h"
19 #include "ui/views/widget/native_widget_mac.h"
20
21 namespace {
22
23 bool WaitForEvent(
24 bool (^dispatch_event_block)(const base::Closure& quit_closure)) {
25 scoped_refptr<content::MessageLoopRunner> runner =
26 new content::MessageLoopRunner;
27 bool result = dispatch_event_block(runner->QuitClosure());
28 runner->Run();
29 return result;
30 }
31
32 bool MouseMove(const gfx::Point& p) {
33 return WaitForEvent(^(const base::Closure& quit_closure) {
34 return ui_controls::SendMouseMoveNotifyWhenDone(p.x(), p.y(), quit_closure);
35 });
36 }
37
38 bool MouseDown() {
39 return WaitForEvent(^(const base::Closure& quit_closure) {
40 return ui_controls::SendMouseEventsNotifyWhenDone(
41 ui_controls::LEFT, ui_controls::DOWN, quit_closure);
42 });
43 }
44
45 bool MouseUp() {
46 return WaitForEvent(^(const base::Closure& quit_closure) {
47 return ui_controls::SendMouseEventsNotifyWhenDone(
48 ui_controls::LEFT, ui_controls::UP, quit_closure);
49 });
50 }
51
52 class ScopedCGEventsEnabler {
53 public:
54 ScopedCGEventsEnabler()
55 : enable_cgevents_(ui_controls::SendMouseEventsAsCGEvents()) {
56 ui_controls::SetSendMouseEventsAsCGEvents(true);
57 }
58
59 ~ScopedCGEventsEnabler() {
60 ui_controls::SetSendMouseEventsAsCGEvents(enable_cgevents_);
61 }
62
63 private:
64 bool enable_cgevents_;
65 };
66
67 void RunAtBackgroundQueue(void (^block)()) {
68 auto queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
69 scoped_refptr<content::MessageLoopRunner> runner =
70 new content::MessageLoopRunner;
71
72 dispatch_async(queue, ^{
73 scoped_ptr<base::MessageLoop> loop(
74 new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
75
76 block();
77
78 dispatch_async(dispatch_get_main_queue(), ^{
79 runner->Quit();
80 });
81 });
82
83 // We need to run the loop on the main thread, so the mouse events will be
84 // actually processed.
85 runner->Run();
86 }
87
88 bool WindowIsMoving(NSWindow* window) {
89 views::BridgedNativeWidget* bridge =
90 views::NativeWidgetMac::GetBridgeForNativeWindow(window);
91 DCHECK(bridge);
92 return bridge->IsRunMoveLoopActive();
93 }
94
95 // If current window under the cursor is currently moving by WindowServer, wait
96 // for the NSWindowMovedEventType notification.
97 //
98 // Returns whether the window under the cursor was moved by the system.
99 bool WaitForSystemWindowMoveToStop() {
100 // NOTE: This is a potentially troublesome part, currently it only works
101 // with MacViewsBrowser when the moved window entered RunMoveLoop.
102 // On non-MacViewsBrowser builds or when the window was moved using the
103 // caption we would be unable to detect that the window was moved using the
104 // WindowServer and would not wait for the final NSWindowMovedEventType
105 // notification.
106 //
107 // As a possible solution it would be possible to add an
108 // additional argument to the function
109 // |force_wait_for_system_window_move_to_finish|, and force waiting for
110 // notification if this ever becomes a problem.
111 NSWindow* window =
112 GetLocalProcessWindowAtPoint(views::EventMonitor::GetLastMouseLocation(),
113 std::set<gfx::NativeWindow>());
114 const bool window_is_moving_by_system = window && WindowIsMoving(window);
115
116 if (window_is_moving_by_system) {
117 // Wait for a final NSWindowMovedEventType notification, otherwise
118 // the window won't be in the final position. It arrives asynchronously
119 // after the mouse move events.
120 NSEvent* window_move_event =
121 [NSEvent otherEventWithType:NSAppKitDefined
122 location:NSZeroPoint
123 modifierFlags:0
124 timestamp:0
125 windowNumber:0
126 context:0
127 subtype:NSWindowMovedEventType
128 data1:0
129 data2:0];
130 scoped_refptr<content::MessageLoopRunner> no_window_move_runner =
131 new content::MessageLoopRunner;
132 ui_controls::NotifyWhenEventIsProcessed(
133 window_move_event, no_window_move_runner->QuitClosure());
134 no_window_move_runner->Run();
135 }
136
137 return window_is_moving_by_system;
138 }
139
140 } // namespace
13 141
14 namespace ui_test_utils { 142 namespace ui_test_utils {
15 143
16 void HideNativeWindow(gfx::NativeWindow window) { 144 void HideNativeWindow(gfx::NativeWindow window) {
17 [window orderOut:nil]; 145 [window orderOut:nil];
18 } 146 }
19 147
20 bool ShowAndFocusNativeWindow(gfx::NativeWindow window) { 148 bool ShowAndFocusNativeWindow(gfx::NativeWindow window) {
21 // Make sure an unbundled program can get the input focus. 149 // Make sure an unbundled program can get the input focus.
22 ProcessSerialNumber psn = { 0, kCurrentProcess }; 150 ProcessSerialNumber psn = { 0, kCurrentProcess };
(...skipping 14 matching lines...) Expand all
37 // This is because normal AppKit menu updating does not get invoked when 165 // This is because normal AppKit menu updating does not get invoked when
38 // events are sent via ui_test_utils::SendKeyPressSync. 166 // events are sent via ui_test_utils::SendKeyPressSync.
39 BOOL notification_observed = [async_waiter wait]; 167 BOOL notification_observed = [async_waiter wait];
40 base::RunLoop().RunUntilIdle(); // There may be other events queued. Flush. 168 base::RunLoop().RunUntilIdle(); // There may be other events queued. Flush.
41 NSMenu* file_menu = [[[NSApp mainMenu] itemWithTag:IDC_FILE_MENU] submenu]; 169 NSMenu* file_menu = [[[NSApp mainMenu] itemWithTag:IDC_FILE_MENU] submenu];
42 [[file_menu delegate] menuNeedsUpdate:file_menu]; 170 [[file_menu delegate] menuNeedsUpdate:file_menu];
43 171
44 return !async_waiter || notification_observed; 172 return !async_waiter || notification_observed;
45 } 173 }
46 174
175 void DragAndDrop(const gfx::Point& from,
176 const gfx::Point& to,
177 int steps) {
178 DCHECK_GE(steps, 1);
179
180 ScopedCGEventsEnabler cgevents_enabler;
181
182 RunAtBackgroundQueue(^() {
183 MouseMove(from);
184 MouseDown();
185
186 // If steps is greater than 1, then we need to use CGEvents, otherwise
187 // the CocoaWindowMoveLoop won't actually work, as the window dragging works
188 // on the WindowServer level.
189 for (int i = 1; i <= steps; ++i) {
190 const double progress = static_cast<double>(i) / steps;
191 const gfx::Point p(
192 gfx::Tween::IntValueBetween(progress, from.x(), to.x()),
193 gfx::Tween::IntValueBetween(progress, from.y(), to.y()));
194 MouseMove(p);
195 }
196
197 const bool window_was_moved_by_system = WaitForSystemWindowMoveToStop();
198 if (steps > 1) {
199 ASSERT_TRUE(window_was_moved_by_system);
200 }
201
202 MouseUp();
203 });
204 }
205
47 } // namespace ui_test_utils 206 } // namespace ui_test_utils
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698