OLD | NEW |
---|---|
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 #include "ui/events/test/cocoa_test_event_utils.h" | |
12 #include "ui/views/test/widget_test.h" | 14 #include "ui/views/test/widget_test.h" |
15 #include "ui/views/window/native_frame_view.h" | |
16 | |
17 // Watches for NSNotifications from the default notification center. | |
18 @interface WindowedNSNotificationObserver : NSObject { | |
jackhou1
2015/06/02 06:33:09
This can probably be merged with the one in app_sh
tapted
2015/06/03 00:28:37
are they both called WindowedNSNotificationObserve
jackhou1
2015/06/03 04:04:44
Nope, this one is in macviews_interactive_ui_tests
tapted
2015/06/03 07:04:48
oh whoops - nope. #wirescrossed
| |
19 @private | |
20 BOOL notificationReceived_; | |
21 scoped_ptr<base::RunLoop> runLoop_; | |
22 } | |
23 | |
24 - (id)initForNotification:(NSString*)name; | |
25 - (void)observe:(NSNotification*)notification; | |
26 - (void)wait; | |
27 @end | |
28 | |
29 @implementation WindowedNSNotificationObserver | |
30 | |
31 - (id)initForNotification:(NSString*)name { | |
32 if (self = [super init]) { | |
33 [[NSNotificationCenter defaultCenter] addObserver:self | |
34 selector:@selector(observe:) | |
35 name:name | |
36 object:nil]; | |
37 } | |
38 return self; | |
39 } | |
40 | |
41 - (void)observe:(NSNotification*)notification { | |
42 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
43 notificationReceived_ = YES; | |
44 if (runLoop_.get()) | |
45 runLoop_->Quit(); | |
46 } | |
47 | |
48 - (void)wait { | |
49 if (notificationReceived_) | |
50 return; | |
51 | |
52 runLoop_.reset(new base::RunLoop); | |
53 runLoop_->Run(); | |
54 } | |
55 | |
56 @end | |
13 | 57 |
14 namespace views { | 58 namespace views { |
tapted
2015/06/03 00:28:37
add namespace test { after this (i.e. whole file s
jackhou1
2015/06/03 04:04:44
Done.
| |
15 | 59 |
16 class BridgedNativeWidgetUITest : public test::WidgetTest { | 60 class BridgedNativeWidgetUITest : public test::WidgetTest { |
17 public: | 61 public: |
18 BridgedNativeWidgetUITest() {} | 62 BridgedNativeWidgetUITest() {} |
19 | 63 |
20 // testing::Test: | 64 // testing::Test: |
21 void SetUp() override { | 65 void SetUp() override { |
22 WidgetTest::SetUp(); | 66 WidgetTest::SetUp(); |
23 Widget::InitParams init_params = | 67 Widget::InitParams init_params = |
24 CreateParams(Widget::InitParams::TYPE_WINDOW); | 68 CreateParams(Widget::InitParams::TYPE_WINDOW); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 widget_->SetFullscreen(false); | 181 widget_->SetFullscreen(false); |
138 EXPECT_FALSE(widget_->IsFullscreen()); | 182 EXPECT_FALSE(widget_->IsFullscreen()); |
139 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds()); | 183 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds()); |
140 | 184 |
141 [waiter waitForEnterCount:1 exitCount:1]; | 185 [waiter waitForEnterCount:1 exitCount:1]; |
142 EXPECT_EQ(1, [waiter enterCount]); | 186 EXPECT_EQ(1, [waiter enterCount]); |
143 EXPECT_EQ(1, [waiter exitCount]); | 187 EXPECT_EQ(1, [waiter exitCount]); |
144 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds()); | 188 EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds()); |
145 } | 189 } |
146 | 190 |
191 namespace { | |
192 | |
193 // This is used to wait for reposted events to be seen. We can't just use | |
194 // RunPendingMessages() because CGEventPost might not be synchronous. | |
195 class HitTestBridgedNativeWidget : public BridgedNativeWidget { | |
196 public: | |
197 HitTestBridgedNativeWidget(NativeWidgetMac* widget) | |
198 : BridgedNativeWidget(widget) {} | |
199 | |
200 bool ShouldRepostPendingLeftMouseDown(NSPoint location_in_window) override { | |
201 bool draggable_before = [ns_view() mouseDownCanMoveWindow]; | |
202 bool should_repost = BridgedNativeWidget::ShouldRepostPendingLeftMouseDown( | |
203 location_in_window); | |
204 bool draggable_after = [ns_view() mouseDownCanMoveWindow]; | |
205 | |
206 if (run_loop_.get() && draggable_before && !draggable_after) | |
207 run_loop_->Quit(); | |
208 | |
209 return should_repost; | |
210 } | |
211 | |
212 void WaitForRepost() { | |
213 run_loop_.reset(new base::RunLoop); | |
214 run_loop_->Run(); | |
215 } | |
216 | |
217 private: | |
218 scoped_ptr<base::RunLoop> run_loop_; | |
219 }; | |
220 | |
221 // This is used to return a customized result to NonClientHitTest. | |
222 class HitTestNonClientFrameView : public NativeFrameView { | |
223 public: | |
224 HitTestNonClientFrameView(Widget* widget) | |
225 : NativeFrameView(widget), hit_test_result_(HTNOWHERE) {} | |
226 | |
227 // NonClientFrameView overrides: | |
228 int NonClientHitTest(const gfx::Point& point) override { | |
229 return hit_test_result_; | |
230 } | |
231 | |
232 void set_hit_test_result(int component) { hit_test_result_ = component; } | |
233 | |
234 private: | |
235 int hit_test_result_; | |
236 }; | |
237 | |
238 } // namespace | |
239 | |
240 // This is used to inject test versions of NativeFrameView and | |
241 // BridgedNativeWidget. | |
242 // Outside anonymous namespace so NativeWidgetMac can friend this. | |
243 class HitTestNativeWidgetMac : public NativeWidgetMac { | |
244 public: | |
245 HitTestNativeWidgetMac(internal::NativeWidgetDelegate* delegate, | |
246 NativeFrameView* native_frame_view) | |
247 : NativeWidgetMac(delegate), native_frame_view_(native_frame_view) { | |
248 NativeWidgetMac::bridge_.reset(new HitTestBridgedNativeWidget(this)); | |
249 } | |
250 | |
251 HitTestBridgedNativeWidget* bridge() { | |
252 return static_cast<HitTestBridgedNativeWidget*>( | |
253 NativeWidgetMac::bridge_.get()); | |
254 } | |
255 | |
256 // internal::NativeWidgetPrivate: | |
257 NonClientFrameView* CreateNonClientFrameView() override { | |
258 return native_frame_view_; | |
259 } | |
260 | |
261 private: | |
262 // Owned by Widget. | |
263 NativeFrameView* native_frame_view_; | |
264 }; | |
265 | |
266 TEST_F(BridgedNativeWidgetUITest, HitTest) { | |
267 Widget widget; | |
268 HitTestNonClientFrameView* frame_view = | |
269 new HitTestNonClientFrameView(&widget); | |
270 HitTestNativeWidgetMac* native_widget = | |
271 new HitTestNativeWidgetMac(&widget, frame_view); | |
272 Widget::InitParams init_params = | |
273 CreateParams(Widget::InitParams::TYPE_WINDOW); | |
274 init_params.native_widget = native_widget; | |
275 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
276 init_params.bounds = gfx::Rect(100, 100, 400, 300); | |
277 widget.Init(init_params); | |
278 widget.Show(); | |
279 RunPendingMessages(); | |
280 | |
281 frame_view->set_hit_test_result(HTCAPTION); | |
282 { | |
283 EXPECT_EQ(100, [widget.GetNativeWindow() frame].origin.x); | |
284 | |
285 NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( | |
286 NSMakePoint(10, 10), widget.GetNativeWindow()); | |
287 CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]); | |
288 native_widget->bridge()->WaitForRepost(); | |
289 | |
290 base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer( | |
291 [[WindowedNSNotificationObserver alloc] | |
292 initForNotification:NSWindowDidMoveNotification]); | |
293 NSEvent* mouse_drag = cocoa_test_event_utils::MouseEventAtPointInWindow( | |
294 NSMakePoint(110, 110), NSLeftMouseDragged, widget.GetNativeWindow(), | |
295 1u); | |
296 CGEventPost(kCGSessionEventTap, [mouse_drag CGEvent]); | |
297 [ns_observer wait]; | |
298 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x); | |
299 | |
300 NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow( | |
301 NSMakePoint(110, 110), NSLeftMouseUp, widget.GetNativeWindow(), 2u); | |
302 CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]); | |
303 RunPendingMessages(); | |
304 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x); | |
305 } | |
306 | |
307 frame_view->set_hit_test_result(HTCLIENT); | |
308 { | |
309 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x); | |
310 | |
311 NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( | |
312 NSMakePoint(10, 10), widget.GetNativeWindow()); | |
313 CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]); | |
314 RunPendingMessages(); | |
jackhou1
2015/06/02 06:33:09
I suspect these are not actually waiting long enou
tapted
2015/06/03 00:28:37
hm.... for these kind of events, maybe not without
jackhou1
2015/06/03 04:04:44
Just ended up using a local event monitor.
I had
| |
315 | |
316 NSEvent* mouse_drag = cocoa_test_event_utils::MouseEventAtPointInWindow( | |
317 NSMakePoint(110, 110), NSLeftMouseDragged, widget.GetNativeWindow(), | |
318 3u); | |
319 CGEventPost(kCGSessionEventTap, [mouse_drag CGEvent]); | |
320 RunPendingMessages(); | |
321 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x); | |
322 | |
323 NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow( | |
324 NSMakePoint(110, 110), NSLeftMouseUp, widget.GetNativeWindow(), 4u); | |
325 CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]); | |
326 RunPendingMessages(); | |
327 EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x); | |
328 } | |
329 } | |
330 | |
147 } // namespace views | 331 } // namespace views |
OLD | NEW |