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 #include "ui/views/widget/native_widget_mac.h" | 5 #include "ui/views/widget/native_widget_mac.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #import "base/mac/bind_objc_block.h" | |
12 #include "base/mac/foundation_util.h" | 11 #include "base/mac/foundation_util.h" |
13 #include "base/mac/scoped_nsobject.h" | 12 #include "base/mac/scoped_nsobject.h" |
14 #include "base/strings/sys_string_conversions.h" | 13 #include "base/strings/sys_string_conversions.h" |
15 #include "base/threading/thread_task_runner_handle.h" | |
16 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" | |
17 #import "ui/base/cocoa/window_size_constants.h" | 14 #import "ui/base/cocoa/window_size_constants.h" |
18 #include "ui/gfx/font_list.h" | 15 #include "ui/gfx/font_list.h" |
19 #import "ui/gfx/mac/coordinate_conversion.h" | 16 #import "ui/gfx/mac/coordinate_conversion.h" |
20 #import "ui/gfx/mac/nswindow_frame_controls.h" | 17 #import "ui/gfx/mac/nswindow_frame_controls.h" |
21 #include "ui/native_theme/native_theme.h" | 18 #include "ui/native_theme/native_theme.h" |
22 #include "ui/native_theme/native_theme_mac.h" | 19 #include "ui/native_theme/native_theme_mac.h" |
23 #import "ui/views/cocoa/bridged_content_view.h" | 20 #import "ui/views/cocoa/bridged_content_view.h" |
24 #import "ui/views/cocoa/bridged_native_widget.h" | 21 #import "ui/views/cocoa/bridged_native_widget.h" |
25 #include "ui/views/cocoa/cocoa_mouse_capture.h" | 22 #include "ui/views/cocoa/cocoa_mouse_capture.h" |
26 #import "ui/views/cocoa/drag_drop_client_mac.h" | 23 #import "ui/views/cocoa/drag_drop_client_mac.h" |
27 #import "ui/views/cocoa/native_widget_mac_nswindow.h" | 24 #import "ui/views/cocoa/native_widget_mac_nswindow.h" |
28 #import "ui/views/cocoa/views_nswindow_delegate.h" | 25 #import "ui/views/cocoa/views_nswindow_delegate.h" |
29 #include "ui/views/widget/drop_helper.h" | 26 #include "ui/views/widget/drop_helper.h" |
30 #include "ui/views/widget/widget_delegate.h" | 27 #include "ui/views/widget/widget_delegate.h" |
31 #include "ui/views/window/native_frame_view.h" | 28 #include "ui/views/window/native_frame_view.h" |
32 | 29 |
33 // Self-owning animation delegate that starts a hide animation, then calls | |
34 // -[NSWindow close] when the animation ends, releasing itself. | |
35 @interface ViewsNSWindowCloseAnimator : NSObject<NSAnimationDelegate> { | |
36 @private | |
37 base::scoped_nsobject<NSWindow> window_; | |
38 base::scoped_nsobject<NSAnimation> animation_; | |
39 } | |
40 | |
41 + (void)closeWindowWithAnimation:(NSWindow*)window; | |
42 | |
43 @end | |
44 | |
45 namespace views { | 30 namespace views { |
46 namespace { | 31 namespace { |
47 | 32 |
48 NSInteger StyleMaskForParams(const Widget::InitParams& params) { | 33 NSInteger StyleMaskForParams(const Widget::InitParams& params) { |
49 // If the Widget is modal, it will be displayed as a sheet. This works best if | 34 // If the Widget is modal, it will be displayed as a sheet. This works best if |
50 // it has NSTitledWindowMask. For example, with NSBorderlessWindowMask, the | 35 // it has NSTitledWindowMask. For example, with NSBorderlessWindowMask, the |
51 // parent window still accepts input. | 36 // parent window still accepts input. |
52 if (params.delegate && | 37 if (params.delegate && |
53 params.delegate->GetModalType() == ui::MODAL_TYPE_WINDOW) | 38 params.delegate->GetModalType() == ui::MODAL_TYPE_WINDOW) |
54 return NSTitledWindowMask; | 39 return NSTitledWindowMask; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 gfx::NativeWindow window) { | 73 gfx::NativeWindow window) { |
89 id<NSWindowDelegate> window_delegate = [window delegate]; | 74 id<NSWindowDelegate> window_delegate = [window delegate]; |
90 if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) { | 75 if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) { |
91 ViewsNSWindowDelegate* delegate = | 76 ViewsNSWindowDelegate* delegate = |
92 base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate); | 77 base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate); |
93 return [delegate nativeWidgetMac]->bridge_.get(); | 78 return [delegate nativeWidgetMac]->bridge_.get(); |
94 } | 79 } |
95 return nullptr; // Not created by NativeWidgetMac. | 80 return nullptr; // Not created by NativeWidgetMac. |
96 } | 81 } |
97 | 82 |
98 bool NativeWidgetMac::IsWindowModalSheet() const { | |
99 return GetWidget()->widget_delegate()->GetModalType() == | |
100 ui::MODAL_TYPE_WINDOW; | |
101 } | |
102 | |
103 void NativeWidgetMac::OnWindowWillClose() { | 83 void NativeWidgetMac::OnWindowWillClose() { |
104 // Note: If closed via CloseNow(), |bridge_| will already be reset. If closed | 84 // Note: If closed via CloseNow(), |bridge_| will already be reset. If closed |
105 // by the user, or via Close() and a RunLoop, notify observers while |bridge_| | 85 // by the user, or via Close() and a RunLoop, notify observers while |bridge_| |
106 // is still a valid pointer, then reset it. | 86 // is still a valid pointer, then reset it. |
107 if (bridge_) { | 87 if (bridge_) { |
108 delegate_->OnNativeWidgetDestroying(); | 88 delegate_->OnNativeWidgetDestroying(); |
109 bridge_.reset(); | 89 bridge_.reset(); |
110 } | 90 } |
111 delegate_->OnNativeWidgetDestroyed(); | 91 delegate_->OnNativeWidgetDestroyed(); |
112 if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) | 92 if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 } | 317 } |
338 | 318 |
339 void NativeWidgetMac::SetShape(std::unique_ptr<SkRegion> shape) { | 319 void NativeWidgetMac::SetShape(std::unique_ptr<SkRegion> shape) { |
340 NOTIMPLEMENTED(); | 320 NOTIMPLEMENTED(); |
341 } | 321 } |
342 | 322 |
343 void NativeWidgetMac::Close() { | 323 void NativeWidgetMac::Close() { |
344 if (!bridge_) | 324 if (!bridge_) |
345 return; | 325 return; |
346 | 326 |
347 NSWindow* window = GetNativeWindow(); | 327 bridge_->CloseAsynchronously(); |
348 if (IsWindowModalSheet()) { | |
349 // Sheets can't be closed normally. This starts the sheet closing. Once the | |
350 // sheet has finished animating, it will call sheetDidEnd: on the parent | |
351 // window's delegate. Note it still needs to be asynchronous, since code | |
352 // calling Widget::Close() doesn't expect things to be deleted upon return. | |
353 [NSApp performSelector:@selector(endSheet:) withObject:window afterDelay:0]; | |
354 return; | |
355 } | |
356 | |
357 // For other modal types, animate the close. | |
358 if (delegate_->IsModal()) { | |
359 [ViewsNSWindowCloseAnimator closeWindowWithAnimation:window]; | |
360 return; | |
361 } | |
362 | |
363 // Clear the view early to suppress repaints. | |
364 bridge_->SetRootView(NULL); | |
365 | |
366 // Widget::Close() ensures [Non]ClientView::CanClose() returns true, so there | |
367 // is no need to call the NSWindow or its delegate's -windowShouldClose: | |
368 // implementation in the manner of -[NSWindow performClose:]. But, | |
369 // like -performClose:, first remove the window from AppKit's display | |
370 // list to avoid crashes like http://crbug.com/156101. | |
371 [window orderOut:nil]; | |
372 | |
373 // Many tests assume that base::RunLoop().RunUntilIdle() is always sufficient | |
374 // to execute a close. However, in rare cases, -performSelector:..afterDelay:0 | |
375 // does not do this. So post a regular task. | |
376 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindBlock(^{ | |
377 [window close]; | |
378 })); | |
379 } | 328 } |
380 | 329 |
381 void NativeWidgetMac::CloseNow() { | 330 void NativeWidgetMac::CloseNow() { |
382 if (!bridge_) | 331 if (!bridge_) |
383 return; | 332 return; |
384 | 333 |
385 // Notify observers while |bridged_| is still valid. | 334 // Notify observers while |bridged_| is still valid. |
386 delegate_->OnNativeWidgetDestroying(); | 335 delegate_->OnNativeWidgetDestroying(); |
387 // Reset |bridge_| to NULL before destroying it. | 336 // Reset |bridge_| to NULL before destroying it. |
388 std::unique_ptr<BridgedNativeWidget> bridge(std::move(bridge_)); | 337 std::unique_ptr<BridgedNativeWidget> bridge(std::move(bridge_)); |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 } | 685 } |
737 | 686 |
738 // static | 687 // static |
739 gfx::NativeView NativeWidgetPrivate::GetGlobalCapture( | 688 gfx::NativeView NativeWidgetPrivate::GetGlobalCapture( |
740 gfx::NativeView native_view) { | 689 gfx::NativeView native_view) { |
741 return [CocoaMouseCapture::GetGlobalCaptureWindow() contentView]; | 690 return [CocoaMouseCapture::GetGlobalCaptureWindow() contentView]; |
742 } | 691 } |
743 | 692 |
744 } // namespace internal | 693 } // namespace internal |
745 } // namespace views | 694 } // namespace views |
746 | |
747 @implementation ViewsNSWindowCloseAnimator | |
748 | |
749 - (id)initWithWindow:(NSWindow*)window { | |
750 if ((self = [super init])) { | |
751 window_.reset([window retain]); | |
752 animation_.reset( | |
753 [[ConstrainedWindowAnimationHide alloc] initWithWindow:window]); | |
754 [animation_ setDelegate:self]; | |
755 [animation_ setAnimationBlockingMode:NSAnimationNonblocking]; | |
756 [animation_ startAnimation]; | |
757 } | |
758 return self; | |
759 } | |
760 | |
761 + (void)closeWindowWithAnimation:(NSWindow*)window { | |
762 [[ViewsNSWindowCloseAnimator alloc] initWithWindow:window]; | |
763 } | |
764 | |
765 - (void)animationDidEnd:(NSAnimation*)animation { | |
766 [window_ close]; | |
767 [animation_ setDelegate:nil]; | |
768 [self release]; | |
769 } | |
770 | |
771 @end | |
OLD | NEW |