| Index: ui/views/cocoa/bridged_native_widget.mm
|
| diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
|
| index 16af930118c3a8fdb3e9b673893bcc1a3b7512ef..7a1225ca7de064346ce11887334687304fcd72fd 100644
|
| --- a/ui/views/cocoa/bridged_native_widget.mm
|
| +++ b/ui/views/cocoa/bridged_native_widget.mm
|
| @@ -9,6 +9,7 @@
|
| #include <stdint.h>
|
|
|
| #include "base/logging.h"
|
| +#import "base/mac/bind_objc_block.h"
|
| #import "base/mac/foundation_util.h"
|
| #include "base/mac/mac_util.h"
|
| #import "base/mac/sdk_forward_declarations.h"
|
| @@ -28,6 +29,7 @@
|
| #import "ui/views/cocoa/cocoa_mouse_capture.h"
|
| #import "ui/views/cocoa/cocoa_window_move_loop.h"
|
| #include "ui/views/cocoa/tooltip_manager_mac.h"
|
| +#import "ui/views/cocoa/views_nswindow_close_animator.h"
|
| #import "ui/views/cocoa/views_nswindow_delegate.h"
|
| #import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
|
| #include "ui/views/view.h"
|
| @@ -350,7 +352,7 @@ BridgedNativeWidget::~BridgedNativeWidget() {
|
| // DialogClientView assumes its delegate is alive when closing, which isn't
|
| // true after endSheet: synchronously calls OnNativeWidgetDestroyed().
|
| // So ban it. Modal dialogs should be closed via Widget::Close().
|
| - DCHECK(!native_widget_mac_->IsWindowModalSheet());
|
| + DCHECK(!IsWindowModalSheet());
|
|
|
| // If the delegate is still set, it means OnWindowWillClose() has not been
|
| // called and the window is still open. Usually, -[NSWindow close] would
|
| @@ -494,7 +496,7 @@ void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
|
| DCHECK(!clamped_content_size.IsEmpty())
|
| << "Zero-sized windows not supported on Mac";
|
|
|
| - if (!window_visible_ && native_widget_mac_->IsWindowModalSheet()) {
|
| + if (!window_visible_ && IsWindowModalSheet()) {
|
| // Window-Modal dialogs (i.e. sheets) are positioned by Cocoa when shown for
|
| // the first time. They also have no frame, so just update the content size.
|
| [window_ setContentSize:NSMakeSize(clamped_content_size.width(),
|
| @@ -559,7 +561,7 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) {
|
| if (parent() && !parent()->IsVisibleParent())
|
| return;
|
|
|
| - if (native_widget_mac_->IsWindowModalSheet()) {
|
| + if (IsWindowModalSheet()) {
|
| ShowAsModalSheet();
|
| return;
|
| }
|
| @@ -596,6 +598,46 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) {
|
| }
|
| }
|
|
|
| +void BridgedNativeWidget::CloseAsynchronously() {
|
| + // In a past life, the window would be synchronously hidden for the non-modal
|
| + // case. AppKit UI could do funny things before an asynchronous close finished
|
| + // (see http://crbug.com/156101). But that shouldn't be needed with toolkit-
|
| + // views. But a synchronous hide would have released capture, so do it now.
|
| + ReleaseCapture();
|
| +
|
| + if (IsWindowModalSheet()) {
|
| + // Sheets can't be closed normally. This starts the sheet closing. Once the
|
| + // sheet has finished animating, it will call sheetDidEnd: on the parent
|
| + // window's delegate. Note it still needs to be asynchronous, since code
|
| + // calling Widget::Close() doesn't expect things to be deleted upon return.
|
| + [NSApp performSelector:@selector(endSheet:)
|
| + withObject:window_
|
| + afterDelay:0];
|
| + return;
|
| + }
|
| +
|
| + // For other modal types, animate the close.
|
| + if (native_widget_mac_->GetWidget()->IsModal()) {
|
| + CloseNativeWindowWithAnimation(window_);
|
| + return;
|
| + }
|
| +
|
| + // Clear the view early to suppress repaints.
|
| + SetRootView(nullptr);
|
| +
|
| + // Widget::Close() ensures [Non]ClientView::CanClose() returns true, so there
|
| + // is no need to call the NSWindow or its delegate's -windowShouldClose:
|
| + // implementation in the manner of -[NSWindow performClose:].
|
| +
|
| + // Many tests assume that base::RunLoop().RunUntilIdle() is always sufficient
|
| + // to execute a close. However, in rare cases, -performSelector:..afterDelay:0
|
| + // does not do this. So post a regular task.
|
| + NSWindow* window = window_; // Ensure the block retains the window.
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindBlock(^{
|
| + [window close];
|
| + }));
|
| +}
|
| +
|
| void BridgedNativeWidget::AcquireCapture() {
|
| DCHECK(!HasCapture());
|
| if (!window_visible_)
|
| @@ -809,6 +851,21 @@ void BridgedNativeWidget::OnVisibilityChanged() {
|
| [parent_->GetNSWindow() removeChildWindow:window_];
|
| }
|
|
|
| + NotifyVisibilityChangeDown();
|
| +
|
| + // Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking
|
| + // for an "empty" draw, disable auto-display while hidden. For example, this
|
| + // prevents Cocoa drawing just *after* a minimize, resulting in a blank window
|
| + // represented in the deminiaturize animation.
|
| + [window_ setAutodisplay:window_visible_];
|
| +
|
| + // |bridged_view_| is null when an asynchronous close is pending. Don't
|
| + // propagate the change further. Note it's not possible to block window
|
| + // visibility changes coming from native messages, so the bookkeeping above
|
| + // should still be done.
|
| + if (!bridged_view_)
|
| + return;
|
| +
|
| // TODO(tapted): Investigate whether we want this for Mac. This is what Aura
|
| // does, and it is what tests expect. However, because layer drawing is
|
| // asynchronous (and things like deminiaturize in AppKit are not), it can
|
| @@ -821,16 +878,8 @@ void BridgedNativeWidget::OnVisibilityChanged() {
|
| layer()->SchedulePaint(gfx::Rect(GetClientAreaSize()));
|
| }
|
|
|
| - NotifyVisibilityChangeDown();
|
| -
|
| native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
|
| window_visible_);
|
| -
|
| - // Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking
|
| - // for an "empty" draw, disable auto-display while hidden. For example, this
|
| - // prevents Cocoa drawing just *after* a minimize, resulting in a blank window
|
| - // represented in the deminiaturize animation.
|
| - [window_ setAutodisplay:window_visible_];
|
| }
|
|
|
| void BridgedNativeWidget::OnBackingPropertiesChanged() {
|
| @@ -962,7 +1011,7 @@ void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type,
|
| // the composited layer. This assumes the native window shape is a good match
|
| // for the composited NonClientFrameView, which should be the case since the
|
| // native shape is what's most appropriate for displaying sheets on Mac.
|
| - if (translucent && !native_widget_mac_->IsWindowModalSheet()) {
|
| + if (translucent && !IsWindowModalSheet()) {
|
| [window_ setOpaque:NO];
|
| // For Mac OS versions earlier than Yosemite, the Window server isn't able
|
| // to generate a window shadow from the composited CALayer. To get around
|
| @@ -1320,6 +1369,11 @@ void BridgedNativeWidget::MaybeWaitForFrame(const gfx::Size& size_in_dip) {
|
| }
|
| }
|
|
|
| +bool BridgedNativeWidget::IsWindowModalSheet() const {
|
| + return native_widget_mac_->GetWidget()->widget_delegate()->GetModalType() ==
|
| + ui::MODAL_TYPE_WINDOW;
|
| +}
|
| +
|
| void BridgedNativeWidget::ShowAsModalSheet() {
|
| // -[NSApp beginSheet:] will block the UI thread while the animation runs.
|
| // So that it doesn't animate a fully transparent window, first wait for a
|
|
|