Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Unified Diff: ui/views/cocoa/bridged_native_widget.mm

Issue 2061693003: MacViews: Suppress visibility changes during an asynchronous close. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Neater, but Linux, Windows disagree on WidgetTest.DesktopNativeWidgetVisibilityAfterCloseTest Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/cocoa/views_nswindow_close_animator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/cocoa/views_nswindow_close_animator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698