Chromium Code Reviews| 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 |