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

Side by Side Diff: ui/views/cocoa/bridged_native_widget_interactive_uitest.mm

Issue 1146873002: [MacViews] Enable dragging a window by its caption/draggable areas. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments. Created 5 years, 6 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 #import "ui/views/cocoa/bridged_native_widget.h" 5 #import "ui/views/cocoa/bridged_native_widget.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 8
9 #import "base/mac/mac_util.h" 9 #import "base/mac/mac_util.h"
10 #import "base/mac/sdk_forward_declarations.h" 10 #import "base/mac/sdk_forward_declarations.h"
11 #import "ui/base/test/nswindow_fullscreen_notification_waiter.h" 11 #import "ui/base/test/nswindow_fullscreen_notification_waiter.h"
12 #include "ui/base/hit_test.h"
13 #import "ui/base/test/windowed_nsnotification_observer.h"
14 #include "ui/events/test/cocoa_test_event_utils.h"
12 #include "ui/views/test/widget_test.h" 15 #include "ui/views/test/widget_test.h"
16 #include "ui/views/window/native_frame_view.h"
13 17
14 namespace views { 18 namespace views {
19 namespace test {
15 20
16 class BridgedNativeWidgetUITest : public test::WidgetTest { 21 class BridgedNativeWidgetUITest : public test::WidgetTest {
17 public: 22 public:
18 BridgedNativeWidgetUITest() {} 23 BridgedNativeWidgetUITest() {}
19 24
20 // testing::Test: 25 // testing::Test:
21 void SetUp() override { 26 void SetUp() override {
22 WidgetTest::SetUp(); 27 WidgetTest::SetUp();
23 Widget::InitParams init_params = 28 Widget::InitParams init_params =
24 CreateParams(Widget::InitParams::TYPE_WINDOW); 29 CreateParams(Widget::InitParams::TYPE_WINDOW);
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 widget_->SetFullscreen(false); 142 widget_->SetFullscreen(false);
138 EXPECT_FALSE(widget_->IsFullscreen()); 143 EXPECT_FALSE(widget_->IsFullscreen());
139 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds()); 144 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
140 145
141 [waiter waitForEnterCount:1 exitCount:1]; 146 [waiter waitForEnterCount:1 exitCount:1];
142 EXPECT_EQ(1, [waiter enterCount]); 147 EXPECT_EQ(1, [waiter enterCount]);
143 EXPECT_EQ(1, [waiter exitCount]); 148 EXPECT_EQ(1, [waiter exitCount]);
144 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds()); 149 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
145 } 150 }
146 151
152 namespace {
153
154 // This is used to wait for reposted events to be seen. We can't just use
155 // RunPendingMessages() because CGEventPost might not be synchronous.
156 class HitTestBridgedNativeWidget : public BridgedNativeWidget {
157 public:
158 HitTestBridgedNativeWidget(NativeWidgetMac* widget)
159 : BridgedNativeWidget(widget) {}
160
161 bool ShouldRepostPendingLeftMouseDown(NSPoint location_in_window) override {
162 bool draggable_before = [ns_view() mouseDownCanMoveWindow];
163 bool should_repost = BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(
164 location_in_window);
165 bool draggable_after = [ns_view() mouseDownCanMoveWindow];
166
167 if (run_loop_.get() && draggable_before && !draggable_after)
168 run_loop_->Quit();
169
170 return should_repost;
171 }
172
173 void WaitForRepost() {
174 run_loop_.reset(new base::RunLoop);
175 run_loop_->Run();
176 }
177
178 private:
179 scoped_ptr<base::RunLoop> run_loop_;
180 };
181
182 // This is used to return a customized result to NonClientHitTest.
183 class HitTestNonClientFrameView : public NativeFrameView {
184 public:
185 HitTestNonClientFrameView(Widget* widget)
186 : NativeFrameView(widget), hit_test_result_(HTNOWHERE) {}
187
188 // NonClientFrameView overrides:
189 int NonClientHitTest(const gfx::Point& point) override {
190 return hit_test_result_;
191 }
192
193 void set_hit_test_result(int component) { hit_test_result_ = component; }
194
195 private:
196 int hit_test_result_;
197 };
198
199 void WaitForEvent(NSUInteger mask) {
200 // Pointer because the handler block captures local variables by copying.
tapted 2015/06/03 07:04:49 what about base::RunLoop run_loop; base::RunLoop*
jackhou1 2015/06/03 08:13:52 Done.
201 base::RunLoop* run_loop = new base::RunLoop();
202 id monitor = [NSEvent
203 addLocalMonitorForEventsMatchingMask:mask
204 handler:^NSEvent*(NSEvent* ns_event) {
205 run_loop->Quit();
206 return ns_event;
207 }];
208 run_loop->Run();
209 [NSEvent removeMonitor:monitor];
210 delete run_loop;
211 }
212
213 } // namespace
214
215 // This is used to inject test versions of NativeFrameView and
216 // BridgedNativeWidget.
217 class HitTestNativeWidgetMac : public NativeWidgetMac {
218 public:
219 HitTestNativeWidgetMac(internal::NativeWidgetDelegate* delegate,
220 NativeFrameView* native_frame_view)
221 : NativeWidgetMac(delegate), native_frame_view_(native_frame_view) {
222 NativeWidgetMac::bridge_.reset(new HitTestBridgedNativeWidget(this));
223 }
224
225 HitTestBridgedNativeWidget* bridge() {
226 return static_cast<HitTestBridgedNativeWidget*>(
227 NativeWidgetMac::bridge_.get());
228 }
229
230 // internal::NativeWidgetPrivate:
231 NonClientFrameView* CreateNonClientFrameView() override {
232 return native_frame_view_;
233 }
234
235 private:
236 // Owned by Widget.
237 NativeFrameView* native_frame_view_;
238 };
tapted 2015/06/03 07:04:49 DISALLOW_COPY_AND_ASSIGN(..)
jackhou1 2015/06/03 08:13:52 Done.
239
240 TEST_F(BridgedNativeWidgetUITest, HitTest) {
241 Widget widget;
242 HitTestNonClientFrameView* frame_view =
243 new HitTestNonClientFrameView(&widget);
244 test::HitTestNativeWidgetMac* native_widget =
245 new test::HitTestNativeWidgetMac(&widget, frame_view);
246 Widget::InitParams init_params =
247 CreateParams(Widget::InitParams::TYPE_WINDOW);
248 init_params.native_widget = native_widget;
249 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
250 init_params.bounds = gfx::Rect(100, 200, 400, 300);
251 widget.Init(init_params);
252 widget.Show();
253 RunPendingMessages();
tapted 2015/06/03 07:04:49 is this needed?
jackhou1 2015/06/03 08:13:52 Done.
254
255 // Dragging the window should work.
256 frame_view->set_hit_test_result(HTCAPTION);
257 {
258 EXPECT_EQ(100, [widget.GetNativeWindow() frame].origin.x);
259
260 NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
261 NSMakePoint(10, 10), widget.GetNativeWindow());
262 CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
263 native_widget->bridge()->WaitForRepost();
264
265 base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
266 [[WindowedNSNotificationObserver alloc]
267 initForNotification:NSWindowDidMoveNotification]);
268 NSEvent* mouse_drag = cocoa_test_event_utils::MouseEventAtPointInWindow(
269 NSMakePoint(110, 110), NSLeftMouseDragged, widget.GetNativeWindow(), 0);
270 CGEventPost(kCGSessionEventTap, [mouse_drag CGEvent]);
271 [ns_observer wait];
272 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
273
274 NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow(
275 NSMakePoint(10, 10), NSLeftMouseUp, widget.GetNativeWindow(), 0);
276 CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
277 WaitForEvent(NSLeftMouseUpMask);
278 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
279 }
280
281 // Mouse-downs on the window controls should not be intercepted.
282 {
283 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
284
285 base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
286 [[WindowedNSNotificationObserver alloc]
287 initForNotification:NSWindowDidMiniaturizeNotification]);
288
289 // Position this on the minimize button.
290 NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
291 NSMakePoint(30, 290), widget.GetNativeWindow());
292 CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
293
294 NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow(
295 NSMakePoint(30, 290), NSLeftMouseUp, widget.GetNativeWindow(), 0);
296 CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
297
298 [ns_observer wait];
299 [widget.GetNativeWindow() deminiaturize:nil];
300
301 // Position unchanged.
302 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
303 }
304
305 // Non-draggable areas should do nothing.
306 frame_view->set_hit_test_result(HTCLIENT);
307 {
308 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
309
310 NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
311 NSMakePoint(10, 10), widget.GetNativeWindow());
312 CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
313 WaitForEvent(NSLeftMouseDownMask);
314
315 NSEvent* mouse_drag = cocoa_test_event_utils::MouseEventAtPointInWindow(
316 NSMakePoint(110, 110), NSLeftMouseDragged, widget.GetNativeWindow(), 0);
317 CGEventPost(kCGSessionEventTap, [mouse_drag CGEvent]);
318 WaitForEvent(NSLeftMouseDraggedMask);
319 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
320
321 NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow(
322 NSMakePoint(110, 110), NSLeftMouseUp, widget.GetNativeWindow(), 0);
323 CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
324 WaitForEvent(NSLeftMouseUpMask);
325 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
326 }
327 }
328
329 } // namespace test
147 } // namespace views 330 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698