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 #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 Loading... | |
| 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 |
| OLD | NEW |