Commit de14cc6a authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

MacViews: Remove native parent support

Require that the parent of a NativeWidgetMac always be either
- an NSView in the NSWindow of another NativeWidgetMac
- a nil NSView

Remove WidgetOwnerNSWindowAdapter (which enabled this functionality)
and BridgedNativeWidgetOwner (the interface it implements).

Update tests that happen to use this functionality so that they don't
use native view parents.

Bug: 859152
Change-Id: I69ea160852be5a44c7e2952445bd1115de72bd8e
Reviewed-on: https://chromium-review.googlesource.com/c/1258292
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596465}
parent 14e8e7cc
...@@ -447,15 +447,12 @@ jumbo_component("views") { ...@@ -447,15 +447,12 @@ jumbo_component("views") {
"../views_bridge_mac/bridged_content_view.h", "../views_bridge_mac/bridged_content_view.h",
"../views_bridge_mac/bridged_content_view.mm", "../views_bridge_mac/bridged_content_view.mm",
"../views_bridge_mac/bridged_content_view_touch_bar.mm", "../views_bridge_mac/bridged_content_view_touch_bar.mm",
"../views_bridge_mac/bridged_native_widget_owner.h",
"../views_bridge_mac/cocoa_window_move_loop.h", "../views_bridge_mac/cocoa_window_move_loop.h",
"../views_bridge_mac/cocoa_window_move_loop.mm", "../views_bridge_mac/cocoa_window_move_loop.mm",
"../views_bridge_mac/views_nswindow_delegate.h", "../views_bridge_mac/views_nswindow_delegate.h",
"../views_bridge_mac/views_nswindow_delegate.mm", "../views_bridge_mac/views_nswindow_delegate.mm",
"../views_bridge_mac/views_scrollbar_bridge.h", "../views_bridge_mac/views_scrollbar_bridge.h",
"../views_bridge_mac/views_scrollbar_bridge.mm", "../views_bridge_mac/views_scrollbar_bridge.mm",
"../views_bridge_mac/widget_owner_nswindow_adapter.h",
"../views_bridge_mac/widget_owner_nswindow_adapter.mm",
"cocoa/bridge_factory_host.cc", "cocoa/bridge_factory_host.cc",
"cocoa/bridged_native_widget_host_impl.h", "cocoa/bridged_native_widget_host_impl.h",
"cocoa/bridged_native_widget_host_impl.mm", "cocoa/bridged_native_widget_host_impl.mm",
......
...@@ -234,7 +234,7 @@ gfx::Vector2d BridgedNativeWidgetHostImpl::GetBoundsOffsetForParent() const { ...@@ -234,7 +234,7 @@ gfx::Vector2d BridgedNativeWidgetHostImpl::GetBoundsOffsetForParent() const {
if (!bridge_impl_) if (!bridge_impl_)
return offset; return offset;
Widget* widget = native_widget_mac_->GetWidget(); Widget* widget = native_widget_mac_->GetWidget();
BridgedNativeWidgetOwner* parent = bridge_impl_->parent(); BridgedNativeWidgetImpl* parent = bridge_impl_->parent();
if (parent && !PositionWindowInScreenCoordinates(widget, widget_type_)) if (parent && !PositionWindowInScreenCoordinates(widget, widget_type_))
offset = parent->GetChildWindowOffset(); offset = parent->GetChildWindowOffset();
return offset; return offset;
......
...@@ -339,7 +339,7 @@ void NativeWidgetMac::SetBoundsConstrained(const gfx::Rect& bounds) { ...@@ -339,7 +339,7 @@ void NativeWidgetMac::SetBoundsConstrained(const gfx::Rect& bounds) {
NativeWidgetPrivate* ancestor = nullptr; NativeWidgetPrivate* ancestor = nullptr;
if (bridge_impl() && bridge_impl()->parent()) { if (bridge_impl() && bridge_impl()->parent()) {
ancestor = ancestor =
GetNativeWidgetForNativeWindow(bridge_impl()->parent()->GetNSWindow()); GetNativeWidgetForNativeWindow(bridge_impl()->parent()->ns_window());
} }
if (!ancestor) { if (!ancestor) {
new_bounds = ConstrainBoundsToDisplayWorkArea(new_bounds); new_bounds = ConstrainBoundsToDisplayWorkArea(new_bounds);
...@@ -729,8 +729,7 @@ NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget( ...@@ -729,8 +729,7 @@ NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
NativeWidgetPrivate* ancestor = NativeWidgetPrivate* ancestor =
bridge_host->bridge_impl()->parent() bridge_host->bridge_impl()->parent()
? GetTopLevelNativeWidget( ? GetTopLevelNativeWidget(
[bridge_host->bridge_impl()->parent()->GetNSWindow() [bridge_host->bridge_impl()->parent()->ns_window() contentView])
contentView])
: nullptr; : nullptr;
return ancestor ? ancestor : bridge_host->native_widget_mac(); return ancestor ? ancestor : bridge_host->native_widget_mac();
} }
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#import "ui/views_bridge_mac/bridged_content_view.h" #import "ui/views_bridge_mac/bridged_content_view.h"
#import "ui/views_bridge_mac/bridged_native_widget_impl.h" #import "ui/views_bridge_mac/bridged_native_widget_impl.h"
#import "ui/views_bridge_mac/native_widget_mac_nswindow.h" #import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
#include "ui/views_bridge_mac/widget_owner_nswindow_adapter.h"
// Donates an implementation of -[NSAnimation stopAnimation] which calls the // Donates an implementation of -[NSAnimation stopAnimation] which calls the
// original implementation, then quits a nested run loop. // original implementation, then quits a nested run loop.
...@@ -87,10 +86,6 @@ ...@@ -87,10 +86,6 @@
@interface FocusableTestNSView : NSView @interface FocusableTestNSView : NSView
@end @end
@interface TestNativeParentWindow : NSWindow
@property(assign, nonatomic) bool* deallocFlag;
@end
namespace views { namespace views {
namespace test { namespace test {
...@@ -155,25 +150,27 @@ class NativeWidgetMacTest : public WidgetTest { ...@@ -155,25 +150,27 @@ class NativeWidgetMacTest : public WidgetTest {
public: public:
NativeWidgetMacTest() {} NativeWidgetMacTest() {}
// The content size of NSWindows made by MakeNativeParent(). // Make an NSWindow with a close button and a title bar to use as a parent.
NSRect ParentRect() const { return NSMakeRect(100, 100, 300, 200); } // This NSWindow is backed by a widget that is not exposed to the caller.
// To destroy the Widget, the native NSWindow must be closed.
// Make a native NSWindow with the given |style_mask| to use as a parent. NativeWidgetMacTestWindow* MakeClosableTitledNativeParent() {
TestNativeParentWindow* MakeNativeParentWithStyle(int style_mask) { NativeWidgetMacTestWindow* native_parent = nil;
WidgetOwnerNSWindowAdapter::AllowForTesting(); Widget::InitParams parent_init_params =
native_parent_.reset([[TestNativeParentWindow alloc] CreateParams(Widget::InitParams::TYPE_WINDOW);
initWithContentRect:ParentRect() parent_init_params.bounds = gfx::Rect(100, 100, 200, 200);
styleMask:style_mask CreateWidgetWithTestWindow(parent_init_params, &native_parent);
backing:NSBackingStoreBuffered return native_parent;
defer:NO]);
[native_parent_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
[native_parent_ makeKeyAndOrderFront:nil];
return native_parent_;
} }
// Make a borderless, native NSWindow to use as a parent. // Same as the above, but creates a borderless NSWindow.
TestNativeParentWindow* MakeNativeParent() { NativeWidgetMacTestWindow* MakeBorderlessNativeParent() {
return MakeNativeParentWithStyle(NSBorderlessWindowMask); NativeWidgetMacTestWindow* native_parent = nil;
Widget::InitParams parent_init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
parent_init_params.remove_standard_frame = true;
parent_init_params.bounds = gfx::Rect(100, 100, 200, 200);
CreateWidgetWithTestWindow(parent_init_params, &native_parent);
return native_parent;
} }
// Create a Widget backed by the NativeWidgetMacTestWindow NSWindow subclass. // Create a Widget backed by the NativeWidgetMacTestWindow NSWindow subclass.
...@@ -189,9 +186,6 @@ class NativeWidgetMacTest : public WidgetTest { ...@@ -189,9 +186,6 @@ class NativeWidgetMacTest : public WidgetTest {
return widget; return widget;
} }
protected:
base::scoped_nsobject<TestNativeParentWindow> native_parent_;
private: private:
DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacTest); DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacTest);
}; };
...@@ -742,26 +736,27 @@ Widget* AttachPopupToNativeParent(NSWindow* native_parent) { ...@@ -742,26 +736,27 @@ Widget* AttachPopupToNativeParent(NSWindow* native_parent) {
// Tests creating a views::Widget parented off a native NSWindow. // Tests creating a views::Widget parented off a native NSWindow.
TEST_F(NativeWidgetMacTest, NonWidgetParent) { TEST_F(NativeWidgetMacTest, NonWidgetParent) {
NSWindow* native_parent = MakeNativeParent(); NSWindow* native_parent = MakeBorderlessNativeParent();
Widget::Widgets children; Widget::Widgets children;
Widget::GetAllChildWidgets([native_parent contentView], &children); Widget::GetAllChildWidgets([native_parent contentView], &children);
EXPECT_TRUE(children.empty()); EXPECT_EQ(1u, children.size());
Widget* child = AttachPopupToNativeParent(native_parent); Widget* child = AttachPopupToNativeParent(native_parent);
TestWidgetObserver child_observer(child); TestWidgetObserver child_observer(child);
// GetTopLevelNativeWidget() only goes as far as there exists a Widget (i.e. // GetTopLevelNativeWidget() will go up through |native_parent|'s Widget.
// must stop at |child|.
internal::NativeWidgetPrivate* top_level_widget = internal::NativeWidgetPrivate* top_level_widget =
internal::NativeWidgetPrivate::GetTopLevelNativeWidget( internal::NativeWidgetPrivate::GetTopLevelNativeWidget(
child->GetNativeView()); child->GetNativeView());
EXPECT_EQ(child, top_level_widget->GetWidget()); EXPECT_EQ(Widget::GetWidgetForNativeWindow(native_parent),
top_level_widget->GetWidget());
EXPECT_NE(child, top_level_widget->GetWidget());
// To verify the parent, we need to use NativeWidgetMac APIs. // To verify the parent, we need to use NativeWidgetMac APIs.
BridgedNativeWidgetImpl* bridged_native_widget = BridgedNativeWidgetImpl* bridged_native_widget =
BridgedNativeWidgetImpl::GetFromNativeWindow(child->GetNativeWindow()); BridgedNativeWidgetImpl::GetFromNativeWindow(child->GetNativeWindow());
EXPECT_EQ(native_parent, bridged_native_widget->parent()->GetNSWindow()); EXPECT_EQ(native_parent, bridged_native_widget->parent()->ns_window());
const gfx::Rect child_bounds(50, 50, 200, 100); const gfx::Rect child_bounds(50, 50, 200, 100);
child->SetBounds(child_bounds); child->SetBounds(child_bounds);
...@@ -776,8 +771,8 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) { ...@@ -776,8 +771,8 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
EXPECT_EQ(native_parent, [child->GetNativeWindow() parentWindow]); EXPECT_EQ(native_parent, [child->GetNativeWindow() parentWindow]);
Widget::GetAllChildWidgets([native_parent contentView], &children); Widget::GetAllChildWidgets([native_parent contentView], &children);
ASSERT_EQ(1u, children.size()); ASSERT_EQ(2u, children.size());
EXPECT_EQ(child, *children.begin()); EXPECT_EQ(1u, children.count(child));
// Only non-toplevel Widgets are positioned relative to the parent, so the // Only non-toplevel Widgets are positioned relative to the parent, so the
// bounds set above should be in screen coordinates. // bounds set above should be in screen coordinates.
...@@ -788,7 +783,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) { ...@@ -788,7 +783,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
NSView* anchor_view = [[native_parent contentView] subviews][0]; NSView* anchor_view = [[native_parent contentView] subviews][0];
EXPECT_TRUE(anchor_view); EXPECT_TRUE(anchor_view);
[anchor_view removeFromSuperview]; [anchor_view removeFromSuperview];
EXPECT_EQ(native_parent, bridged_native_widget->parent()->GetNSWindow()); EXPECT_EQ(native_parent, bridged_native_widget->parent()->ns_window());
// Closing the parent should close and destroy the child. // Closing the parent should close and destroy the child.
EXPECT_FALSE(child_observer.widget_closed()); EXPECT_FALSE(child_observer.widget_closed());
...@@ -796,6 +791,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) { ...@@ -796,6 +791,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
EXPECT_TRUE(child_observer.widget_closed()); EXPECT_TRUE(child_observer.widget_closed());
EXPECT_EQ(0u, [[native_parent childWindows] count]); EXPECT_EQ(0u, [[native_parent childWindows] count]);
[native_parent close];
} }
// Tests that CloseAllSecondaryWidgets behaves in various configurations. // Tests that CloseAllSecondaryWidgets behaves in various configurations.
...@@ -873,15 +869,16 @@ TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) { ...@@ -873,15 +869,16 @@ TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) {
TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) { TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
bool child_dealloced = false; bool child_dealloced = false;
bool native_parent_dealloced = false; bool native_parent_dealloced = false;
NativeWidgetMacTestWindow* native_parent = nil;
{ {
base::mac::ScopedNSAutoreleasePool pool; base::mac::ScopedNSAutoreleasePool pool;
TestNativeParentWindow* native_parent = MakeNativeParent(); native_parent = MakeBorderlessNativeParent();
[native_parent setDeallocFlag:&native_parent_dealloced]; [native_parent setDeallocFlag:&native_parent_dealloced];
NativeWidgetMacTestWindow* window; NativeWidgetMacTestWindow* window;
Widget::InitParams init_params = Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_POPUP); CreateParams(Widget::InitParams::TYPE_POPUP);
init_params.parent = [native_parent_ contentView]; init_params.parent = [native_parent contentView];
init_params.bounds = gfx::Rect(0, 0, 100, 200); init_params.bounds = gfx::Rect(0, 0, 100, 200);
CreateWidgetWithTestWindow(init_params, &window); CreateWidgetWithTestWindow(init_params, &window);
[window setDeallocFlag:&child_dealloced]; [window setDeallocFlag:&child_dealloced];
...@@ -893,7 +890,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) { ...@@ -893,7 +890,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
// to the child window is released inside WidgetOwnerNSWindowAdapter:: // to the child window is released inside WidgetOwnerNSWindowAdapter::
// OnWindowWillClose(). // OnWindowWillClose().
base::mac::ScopedNSAutoreleasePool pool; base::mac::ScopedNSAutoreleasePool pool;
[native_parent_.autorelease() close]; [native_parent close];
EXPECT_TRUE(child_dealloced); EXPECT_TRUE(child_dealloced);
} }
EXPECT_TRUE(native_parent_dealloced); EXPECT_TRUE(native_parent_dealloced);
...@@ -902,7 +899,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) { ...@@ -902,7 +899,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
// Tests visibility for child of native NSWindow, reshowing after -[NSApp hide]. // Tests visibility for child of native NSWindow, reshowing after -[NSApp hide].
// Occasionally flaky (maybe due to [NSApp hide]). See https://crbug.com/777247. // Occasionally flaky (maybe due to [NSApp hide]). See https://crbug.com/777247.
TEST_F(NativeWidgetMacTest, DISABLED_VisibleAfterNativeParentShow) { TEST_F(NativeWidgetMacTest, DISABLED_VisibleAfterNativeParentShow) {
NSWindow* native_parent = MakeNativeParent(); NSWindow* native_parent = MakeBorderlessNativeParent();
Widget* child = AttachPopupToNativeParent(native_parent); Widget* child = AttachPopupToNativeParent(native_parent);
child->Show(); child->Show();
EXPECT_TRUE(child->IsVisible()); EXPECT_TRUE(child->IsVisible());
...@@ -927,7 +924,7 @@ TEST_F(NativeWidgetMacTest, VisibleAfterNativeParentDeminiaturize) { ...@@ -927,7 +924,7 @@ TEST_F(NativeWidgetMacTest, VisibleAfterNativeParentDeminiaturize) {
if (base::mac::IsOS10_10()) if (base::mac::IsOS10_10())
return; return;
NSWindow* native_parent = MakeNativeParent(); NSWindow* native_parent = MakeBorderlessNativeParent();
[native_parent makeKeyAndOrderFront:nil]; [native_parent makeKeyAndOrderFront:nil];
[native_parent miniaturize:nil]; [native_parent miniaturize:nil];
Widget* child = AttachPopupToNativeParent(native_parent); Widget* child = AttachPopupToNativeParent(native_parent);
...@@ -1175,9 +1172,9 @@ Widget* ShowWindowModalWidget(NSWindow* native_parent) { ...@@ -1175,9 +1172,9 @@ Widget* ShowWindowModalWidget(NSWindow* native_parent) {
} // namespace } // namespace
// Tests object lifetime for the show/hide animations used for child-modal // Tests object lifetime for the show/hide animations used for child-modal
// windows. Parents the dialog off a native parent window (not a views::Widget). // windows.
TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) { TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) {
NSWindow* native_parent = MakeNativeParent(); NSWindow* native_parent = MakeBorderlessNativeParent();
{ {
Widget* modal_dialog_widget = ShowChildModalWidgetAndWait(native_parent); Widget* modal_dialog_widget = ShowChildModalWidgetAndWait(native_parent);
TestWidgetObserver widget_observer(modal_dialog_widget); TestWidgetObserver widget_observer(modal_dialog_widget);
...@@ -1230,7 +1227,7 @@ TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) { ...@@ -1230,7 +1227,7 @@ TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) {
// Tests that calls to Hide() a Widget cancel any in-progress show animation, // Tests that calls to Hide() a Widget cancel any in-progress show animation,
// and that clients can control the triggering of the animation. // and that clients can control the triggering of the animation.
TEST_F(NativeWidgetMacTest, ShowAnimationControl) { TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
NSWindow* native_parent = MakeNativeParent(); NSWindow* native_parent = MakeBorderlessNativeParent();
Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget( Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
new ModalDialogDelegate(ui::MODAL_TYPE_CHILD), nullptr, new ModalDialogDelegate(ui::MODAL_TYPE_CHILD), nullptr,
[native_parent contentView]); [native_parent contentView]);
...@@ -1288,8 +1285,7 @@ TEST_F(NativeWidgetMacTest, ShowAnimationControl) { ...@@ -1288,8 +1285,7 @@ TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
// Tests behavior of window-modal dialogs, displayed as sheets. // Tests behavior of window-modal dialogs, displayed as sheets.
TEST_F(NativeWidgetMacTest, WindowModalSheet) { TEST_F(NativeWidgetMacTest, WindowModalSheet) {
NSWindow* native_parent = NSWindow* native_parent = MakeClosableTitledNativeParent();
MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
Widget* sheet_widget = views::DialogDelegate::CreateDialogWidget( Widget* sheet_widget = views::DialogDelegate::CreateDialogWidget(
new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW), nullptr, new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW), nullptr,
...@@ -1330,7 +1326,7 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) { ...@@ -1330,7 +1326,7 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
Widget::Widgets children; Widget::Widgets children;
Widget::GetAllChildWidgets([native_parent contentView], &children); Widget::GetAllChildWidgets([native_parent contentView], &children);
EXPECT_TRUE(children.empty()); ASSERT_EQ(2u, children.size());
sheet_widget->Show(); // Should run the above block, then animate the sheet. sheet_widget->Show(); // Should run the above block, then animate the sheet.
EXPECT_TRUE(did_observe); EXPECT_TRUE(did_observe);
...@@ -1338,8 +1334,8 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) { ...@@ -1338,8 +1334,8 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
// Ensure sheets are included as a child. // Ensure sheets are included as a child.
Widget::GetAllChildWidgets([native_parent contentView], &children); Widget::GetAllChildWidgets([native_parent contentView], &children);
ASSERT_EQ(1u, children.size()); ASSERT_EQ(2u, children.size());
EXPECT_EQ(sheet_widget, *children.begin()); EXPECT_TRUE(children.count(sheet_widget));
// Modal, so the close button in the parent window should get disabled. // Modal, so the close button in the parent window should get disabled.
EXPECT_FALSE([parent_close_button isEnabled]); EXPECT_FALSE([parent_close_button isEnabled]);
...@@ -1370,41 +1366,24 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) { ...@@ -1370,41 +1366,24 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
sheet_widget->Close(); sheet_widget->Close();
EXPECT_TRUE(sheet_widget->IsVisible()); EXPECT_TRUE(sheet_widget->IsVisible());
did_observe = false;
// Experimentally (on 10.10), this notification is posted from within the
// -[NSWindow orderOut:] call that is triggered from -[ViewsNSWindowDelegate
// sheetDidEnd:]. |sheet_widget| will be destroyed next, so it's still safe to
// use in the block. However, since the orderOut just happened, it's not very
// interesting.
observer = [[NSNotificationCenter defaultCenter]
addObserverForName:NSWindowDidEndSheetNotification
object:native_parent
queue:nil
usingBlock:^(NSNotification* note) {
EXPECT_TRUE([sheet_window delegate]);
*did_observe_ptr = true;
}];
// Pump in order to trigger -[NSWindow endSheet:..], which will block while // Pump in order to trigger -[NSWindow endSheet:..], which will block while
// the animation runs, then delete |sheet_widget|. // the animation runs, then delete |sheet_widget|.
EXPECT_TRUE([sheet_window delegate]); EXPECT_TRUE([sheet_window delegate]);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_FALSE([sheet_window delegate]); EXPECT_FALSE([sheet_window delegate]);
EXPECT_TRUE(did_observe); // Also ensures the Close() actually uses sheets.
[[NSNotificationCenter defaultCenter] removeObserver:observer]; [[NSNotificationCenter defaultCenter] removeObserver:observer];
EXPECT_TRUE(widget_observer.widget_closed()); EXPECT_TRUE(widget_observer.widget_closed());
EXPECT_TRUE([parent_close_button isEnabled]); EXPECT_TRUE([parent_close_button isEnabled]);
[native_parent close];
} }
// Tests behavior when closing a window that is a sheet, or that hosts a sheet, // Tests behavior when closing a window that is a sheet, or that hosts a sheet,
// and reshowing a sheet on a window after the sheet was closed with -[NSWindow // and reshowing a sheet on a window after the sheet was closed with -[NSWindow
// close]. // close].
TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) { TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
NSWindow* native_parent = NSWindow* native_parent = MakeClosableTitledNativeParent();
MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
{ {
Widget* sheet_widget = ShowWindowModalWidget(native_parent); Widget* sheet_widget = ShowWindowModalWidget(native_parent);
...@@ -1498,8 +1477,7 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) { ...@@ -1498,8 +1477,7 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
// eventually complete on a destroyed NSWindowDelegate. Regression test for // eventually complete on a destroyed NSWindowDelegate. Regression test for
// https://crbug.com/851376. // https://crbug.com/851376.
TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) { TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) {
NSWindow* native_parent = NSWindow* native_parent = MakeClosableTitledNativeParent();
MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
{ {
base::mac::ScopedNSAutoreleasePool pool; base::mac::ScopedNSAutoreleasePool pool;
Widget* sheet_widget = ShowWindowModalWidget(native_parent); Widget* sheet_widget = ShowWindowModalWidget(native_parent);
...@@ -1543,17 +1521,16 @@ TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) { ...@@ -1543,17 +1521,16 @@ TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) {
} }
// Test calls to Widget::ReparentNativeView() that result in a no-op on Mac. // Test calls to Widget::ReparentNativeView() that result in a no-op on Mac.
// Tests with both native and non-native parents.
TEST_F(NativeWidgetMacTest, NoopReparentNativeView) { TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
NSWindow* parent = MakeNativeParent(); NSWindow* parent = MakeBorderlessNativeParent();
Widget* dialog = views::DialogDelegate::CreateDialogWidget( Widget* dialog = views::DialogDelegate::CreateDialogWidget(
new DialogDelegateView, nullptr, [parent contentView]); new DialogDelegateView, nullptr, [parent contentView]);
BridgedNativeWidgetImpl* bridge = BridgedNativeWidgetImpl* bridge =
BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow()); BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow());
EXPECT_EQ(bridge->parent()->GetNSWindow(), parent); EXPECT_EQ(bridge->parent()->ns_window(), parent);
Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]); Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
EXPECT_EQ(bridge->parent()->GetNSWindow(), parent); EXPECT_EQ(bridge->parent()->ns_window(), parent);
[parent close]; [parent close];
...@@ -1564,9 +1541,9 @@ TEST_F(NativeWidgetMacTest, NoopReparentNativeView) { ...@@ -1564,9 +1541,9 @@ TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
bridge = bridge =
BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow()); BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow());
EXPECT_EQ(bridge->parent()->GetNSWindow(), parent); EXPECT_EQ(bridge->parent()->ns_window(), parent);
Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]); Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
EXPECT_EQ(bridge->parent()->GetNSWindow(), parent); EXPECT_EQ(bridge->parent()->ns_window(), parent);
parent_widget->CloseNow(); parent_widget->CloseNow();
} }
...@@ -2414,18 +2391,3 @@ TEST_F(NativeWidgetMacTest, TouchBar) { ...@@ -2414,18 +2391,3 @@ TEST_F(NativeWidgetMacTest, TouchBar) {
} }
@end @end
@implementation TestNativeParentWindow {
bool* deallocFlag_;
}
@synthesize deallocFlag = deallocFlag_;
- (void)dealloc {
if (deallocFlag_) {
DCHECK(!*deallocFlag_);
*deallocFlag_ = true;
}
[super dealloc];
}
@end
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "ui/base/ime/text_input_client.h" #include "ui/base/ime/text_input_client.h"
#include "ui/display/display_observer.h" #include "ui/display/display_observer.h"
#include "ui/views/views_export.h" #include "ui/views/views_export.h"
#import "ui/views_bridge_mac/bridged_native_widget_owner.h"
#import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h" #import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h"
#include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h" #include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
...@@ -60,8 +59,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl ...@@ -60,8 +59,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
: public views_bridge_mac::mojom::BridgedNativeWidget, : public views_bridge_mac::mojom::BridgedNativeWidget,
public display::DisplayObserver, public display::DisplayObserver,
public ui::CATransactionCoordinator::PreCommitObserver, public ui::CATransactionCoordinator::PreCommitObserver,
public CocoaMouseCaptureDelegate, public CocoaMouseCaptureDelegate {
public BridgedNativeWidgetOwner {
public: public:
// Return the size that |window| will take for the given client area |size|, // Return the size that |window| will take for the given client area |size|,
// based on its current style mask. // based on its current style mask.
...@@ -174,7 +172,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl ...@@ -174,7 +172,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
// The parent widget specified in Widget::InitParams::parent. If non-null, the // The parent widget specified in Widget::InitParams::parent. If non-null, the
// parent will close children before the parent closes, and children will be // parent will close children before the parent closes, and children will be
// raised above their parent when window z-order changes. // raised above their parent when window z-order changes.
BridgedNativeWidgetOwner* parent() { return parent_; } BridgedNativeWidgetImpl* parent() { return parent_; }
const std::vector<BridgedNativeWidgetImpl*>& child_windows() { const std::vector<BridgedNativeWidgetImpl*>& child_windows() {
return child_windows_; return child_windows_;
} }
...@@ -250,6 +248,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl ...@@ -250,6 +248,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
// update widget and compositor size. // update widget and compositor size.
void UpdateWindowGeometry(); void UpdateWindowGeometry();
// The offset in screen pixels for positioning child windows owned by |this|.
gfx::Vector2d GetChildWindowOffset() const;
private: private:
friend class test::BridgedNativeWidgetTestApi; friend class test::BridgedNativeWidgetTestApi;
...@@ -257,6 +258,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl ...@@ -257,6 +258,9 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
// destroyed. // destroyed.
void RemoveOrDestroyChildren(); void RemoveOrDestroyChildren();
// Remove the specified child window without closing it.
void RemoveChildWindow(BridgedNativeWidgetImpl* child);
// Notify descendants of a visibility change. // Notify descendants of a visibility change.
void NotifyVisibilityChangeDown(); void NotifyVisibilityChangeDown();
...@@ -279,12 +283,6 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl ...@@ -279,12 +283,6 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
void OnMouseCaptureLost() override; void OnMouseCaptureLost() override;
NSWindow* GetWindow() const override; NSWindow* GetWindow() const override;
// BridgedNativeWidgetOwner:
NSWindow* GetNSWindow() override;
gfx::Vector2d GetChildWindowOffset() const override;
bool IsVisibleParent() const override;
void RemoveChildWindow(BridgedNativeWidgetImpl* child) override;
const uint64_t id_; const uint64_t id_;
BridgedNativeWidgetHost* const host_; // Weak. Owns this. BridgedNativeWidgetHost* const host_; // Weak. Owns this.
BridgedNativeWidgetHostHelper* const host_helper_; // Weak, owned by |host_|. BridgedNativeWidgetHostHelper* const host_helper_; // Weak, owned by |host_|.
...@@ -299,7 +297,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl ...@@ -299,7 +297,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
bool is_translucent_window_ = false; bool is_translucent_window_ = false;
bool widget_is_top_level_ = false; bool widget_is_top_level_ = false;
BridgedNativeWidgetOwner* parent_ = nullptr; // Weak. If non-null, owns this. BridgedNativeWidgetImpl* parent_ = nullptr; // Weak. If non-null, owns this.
std::vector<BridgedNativeWidgetImpl*> child_windows_; std::vector<BridgedNativeWidgetImpl*> child_windows_;
// The size of the content area of the window most recently sent to |host_| // The size of the content area of the window most recently sent to |host_|
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h" #include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
#import "ui/views_bridge_mac/native_widget_mac_nswindow.h" #import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
#import "ui/views_bridge_mac/views_nswindow_delegate.h" #import "ui/views_bridge_mac/views_nswindow_delegate.h"
#import "ui/views_bridge_mac/widget_owner_nswindow_adapter.h"
using views_bridge_mac::mojom::VisibilityTransition; using views_bridge_mac::mojom::VisibilityTransition;
using views_bridge_mac::mojom::WindowVisibilityState; using views_bridge_mac::mojom::WindowVisibilityState;
...@@ -317,16 +316,16 @@ void BridgedNativeWidgetImpl::SetParent(NSView* new_parent) { ...@@ -317,16 +316,16 @@ void BridgedNativeWidgetImpl::SetParent(NSView* new_parent) {
// Disallow creating child windows of views not currently in an NSWindow. // Disallow creating child windows of views not currently in an NSWindow.
CHECK([new_parent window]); CHECK([new_parent window]);
// It is only valid to have a NativeWidgetMac be the parent of another
// NativeWidgetMac.
CHECK(bridged_native_widget_parent);
// If the parent is another BridgedNativeWidgetImpl, just add to the // If the parent is another BridgedNativeWidgetImpl, just add to the
// collection of child windows it owns and manages. Otherwise, create an // collection of child windows it owns and manages. Otherwise, create an
// adapter to anchor the child widget and observe when the parent NSWindow is // adapter to anchor the child widget and observe when the parent NSWindow is
// closed. // closed.
if (bridged_native_widget_parent) { parent_ = bridged_native_widget_parent;
parent_ = bridged_native_widget_parent; bridged_native_widget_parent->child_windows_.push_back(this);
bridged_native_widget_parent->child_windows_.push_back(this);
} else {
parent_ = new WidgetOwnerNSWindowAdapter(this, new_parent);
}
// Widget::ShowInactive() could result in a Space switch when the widget has a // Widget::ShowInactive() could result in a Space switch when the widget has a
// parent, and we're calling -orderWindow:relativeTo:. Use Transient // parent, and we're calling -orderWindow:relativeTo:. Use Transient
...@@ -569,8 +568,10 @@ void BridgedNativeWidgetImpl::SetVisibilityState( ...@@ -569,8 +568,10 @@ void BridgedNativeWidgetImpl::SetVisibilityState(
// If the parent (or an ancestor) is hidden, return and wait for it to become // If the parent (or an ancestor) is hidden, return and wait for it to become
// visible. // visible.
if (parent() && !parent()->IsVisibleParent()) for (auto* ancestor = parent_; ancestor; ancestor = ancestor->parent_) {
return; if (!ancestor->window_visible_)
return;
}
if (IsWindowModalSheet()) { if (IsWindowModalSheet()) {
ShowAsModalSheet(); ShowAsModalSheet();
...@@ -599,7 +600,7 @@ void BridgedNativeWidgetImpl::SetVisibilityState( ...@@ -599,7 +600,7 @@ void BridgedNativeWidgetImpl::SetVisibilityState(
if (window_visible_) if (window_visible_)
return; // Avoid a Spaces transition. return; // Avoid a Spaces transition.
parent_window_number = [parent_->GetNSWindow() windowNumber]; parent_window_number = [parent_->ns_window() windowNumber];
} }
[window_ orderWindow:NSWindowAbove relativeTo:parent_window_number]; [window_ orderWindow:NSWindowAbove relativeTo:parent_window_number];
...@@ -823,7 +824,7 @@ void BridgedNativeWidgetImpl::OnVisibilityChanged() { ...@@ -823,7 +824,7 @@ void BridgedNativeWidgetImpl::OnVisibilityChanged() {
// Sheets don't need a parentWindow set, and setting one causes graphical // Sheets don't need a parentWindow set, and setting one causes graphical
// glitches (http://crbug.com/605098). // glitches (http://crbug.com/605098).
if (parent_ && ![window_ isSheet]) if (parent_ && ![window_ isSheet])
[parent_->GetNSWindow() addChildWindow:window_ ordered:NSWindowAbove]; [parent_->ns_window() addChildWindow:window_ ordered:NSWindowAbove];
} else { } else {
ReleaseCapture(); // Capture on hidden windows is not permitted. ReleaseCapture(); // Capture on hidden windows is not permitted.
...@@ -831,7 +832,7 @@ void BridgedNativeWidgetImpl::OnVisibilityChanged() { ...@@ -831,7 +832,7 @@ void BridgedNativeWidgetImpl::OnVisibilityChanged() {
// list. Cocoa's childWindow management breaks down when child windows are // list. Cocoa's childWindow management breaks down when child windows are
// hidden. // hidden.
if (parent_) if (parent_)
[parent_->GetNSWindow() removeChildWindow:window_]; [parent_->ns_window() removeChildWindow:window_];
} }
// Showing a translucent window after hiding it should trigger shadow // Showing a translucent window after hiding it should trigger shadow
...@@ -1127,21 +1128,12 @@ void BridgedNativeWidgetImpl::SetTextInputClient( ...@@ -1127,21 +1128,12 @@ void BridgedNativeWidgetImpl::SetTextInputClient(
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetImpl, BridgedNativeWidgetOwner: // BridgedNativeWidgetImpl, former BridgedNativeWidgetOwner:
NSWindow* BridgedNativeWidgetImpl::GetNSWindow() {
return window_;
}
gfx::Vector2d BridgedNativeWidgetImpl::GetChildWindowOffset() const { gfx::Vector2d BridgedNativeWidgetImpl::GetChildWindowOffset() const {
return gfx::ScreenRectFromNSRect([window_ frame]).OffsetFromOrigin(); return gfx::ScreenRectFromNSRect([window_ frame]).OffsetFromOrigin();
} }
bool BridgedNativeWidgetImpl::IsVisibleParent() const {
return parent_ ? window_visible_ && parent_->IsVisibleParent()
: window_visible_;
}
void BridgedNativeWidgetImpl::RemoveChildWindow( void BridgedNativeWidgetImpl::RemoveChildWindow(
BridgedNativeWidgetImpl* child) { BridgedNativeWidgetImpl* child) {
auto location = auto location =
...@@ -1253,7 +1245,7 @@ void BridgedNativeWidgetImpl::ShowAsModalSheet() { ...@@ -1253,7 +1245,7 @@ void BridgedNativeWidgetImpl::ShowAsModalSheet() {
window_visible_ = true; window_visible_ = true;
host_->OnVisibilityChanged(window_visible_); host_->OnVisibilityChanged(window_visible_);
NSWindow* parent_window = parent_->GetNSWindow(); NSWindow* parent_window = parent_->ns_window();
DCHECK(parent_window); DCHECK(parent_window);
// -beginSheet: does not retain |modalDelegate| (and we would not want it to). // -beginSheet: does not retain |modalDelegate| (and we would not want it to).
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_OWNER_H_
#define UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_OWNER_H_
namespace gfx {
class Vector2d;
}
@class NSWindow;
namespace views {
class BridgedNativeWidgetImpl;
// An abstract interface wrapping an NSWindow that ties the lifetime of one or
// more child BridgedNativeWidgets to the lifetime of that NSWindow. This is not
// simply an NSWindow, because the child window API provided by NSWindow
// requires child windows to always be visible.
class BridgedNativeWidgetOwner {
public:
// The NSWindow parent.
virtual NSWindow* GetNSWindow() = 0;
// The offset in screen pixels for positioning child windows owned by |this|.
virtual gfx::Vector2d GetChildWindowOffset() const = 0;
// Return false if |this| is hidden, or has a hidden ancestor.
virtual bool IsVisibleParent() const = 0;
// Removes a child window. Note |this| may be deleted after calling, so the
// caller should immediately null out the pointer used to make the call.
virtual void RemoveChildWindow(BridgedNativeWidgetImpl* child) = 0;
protected:
// Instances of this class may be self-deleting.
virtual ~BridgedNativeWidgetOwner() {}
};
} // namespace views
#endif // UI_VIEWS_BRIDGE_MAC_BRIDGED_NATIVE_WIDGET_OWNER_H_
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_BRIDGE_MAC_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
#define UI_VIEWS_BRIDGE_MAC_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
#import "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#import "ui/views/views_export.h"
#import "ui/views_bridge_mac/bridged_native_widget_owner.h"
@class NSView;
@class NSWindow;
@class WidgetOwnerNSWindowAdapterBridge;
namespace views {
// An adapter that allows a views::Widget to be owned by an NSWindow that is not
// backed by another BridgedNativeWidgetImpl.
class WidgetOwnerNSWindowAdapter : public BridgedNativeWidgetOwner {
public:
// This class appears to be unused outside of NativeWidgetMacTest. This class
// will crash on instantiation unless AllowForTesting is called. If no crashes
// are reported in the wild, then this class may be removed.
// https://832676
static VIEWS_EXPORT void AllowForTesting();
// Create an adapter that will own |child|, tying its lifetime with the
// NSWindow containing |anchor_view|. The object is self-deleting, via a call
// to RemoveChildWindow() made in child->OnWindowWillClose().
WidgetOwnerNSWindowAdapter(BridgedNativeWidgetImpl* child,
NSView* anchor_view);
// Called when the owning window is closing.
void OnWindowWillClose();
// Called when the owning window is hidden or shown.
void OnWindowDidChangeOcclusionState();
// Overridden from BridgedNativeWidgetOwner:
NSWindow* GetNSWindow() override;
gfx::Vector2d GetChildWindowOffset() const override;
bool IsVisibleParent() const override;
void RemoveChildWindow(BridgedNativeWidgetImpl* child) override;
private:
// Self-deleting.
~WidgetOwnerNSWindowAdapter() override;
BridgedNativeWidgetImpl* child_; // Weak. Owned by its NativeWidgetMac.
base::scoped_nsobject<NSView> anchor_view_;
base::scoped_nsobject<NSWindow> anchor_window_;
base::scoped_nsobject<WidgetOwnerNSWindowAdapterBridge> observer_bridge_;
DISALLOW_COPY_AND_ASSIGN(WidgetOwnerNSWindowAdapter);
};
} // namespace views
#endif // UI_VIEWS_BRIDGE_MAC_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ui/views_bridge_mac/widget_owner_nswindow_adapter.h"
#import <Cocoa/Cocoa.h>
#include "base/logging.h"
#include "base/mac/sdk_forward_declarations.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
// Bridges an AppKit observer to observe when the (non-views) NSWindow owning a
// views::Widget will close or change occlusion state.
@interface WidgetOwnerNSWindowAdapterBridge : NSObject {
@private
views::WidgetOwnerNSWindowAdapter* adapter_; // Weak. Owns us.
}
- (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter;
- (void)windowWillClose:(NSNotification*)notification;
- (void)windowDidChangeOcclusionState:(NSNotification*)notification;
@end
@implementation WidgetOwnerNSWindowAdapterBridge
- (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter {
if ((self = [super init]))
adapter_ = adapter;
return self;
}
- (void)windowWillClose:(NSNotification*)notification {
adapter_->OnWindowWillClose();
}
- (void)windowDidChangeOcclusionState:(NSNotification*)notification {
adapter_->OnWindowDidChangeOcclusionState();
}
@end
namespace views {
namespace {
bool g_allow_widget_owner_ns_window_adapter = false;
}
// static
void WidgetOwnerNSWindowAdapter::AllowForTesting() {
g_allow_widget_owner_ns_window_adapter = true;
}
WidgetOwnerNSWindowAdapter::WidgetOwnerNSWindowAdapter(
BridgedNativeWidgetImpl* child,
NSView* anchor_view)
: child_(child),
anchor_view_([anchor_view retain]),
observer_bridge_(
[[WidgetOwnerNSWindowAdapterBridge alloc] initWithAdapter:this]) {
CHECK(g_allow_widget_owner_ns_window_adapter);
// Although the |anchor_view| must be in an NSWindow when the child dialog is
// created, it's permitted for the |anchor_view| to be removed from its view
// hierarchy before the child dialog window is fully removed from screen. When
// this happens, [anchor_view_ window] will become nil, so retain both.
anchor_window_.reset([[anchor_view_ window] retain]);
DCHECK(anchor_window_);
[[NSNotificationCenter defaultCenter]
addObserver:observer_bridge_
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:anchor_window_];
// BridgedNativeWidgetImpl removes NSWindow parent/child relationships for
// hidden windows. Observe when the parent's visibility changes so they can be
// reconnected.
[[NSNotificationCenter defaultCenter]
addObserver:observer_bridge_
selector:@selector(windowDidChangeOcclusionState:)
name:NSWindowDidChangeOcclusionStateNotification
object:anchor_window_];
// On a deminiaturize, the occlusion state change may occur before -[NSWindow
// isVisible] returns YES. So observe NSWindowDidDeminiaturizeNotification.
// This allows the adapter to check again at the end of the deminiaturize.
[[NSNotificationCenter defaultCenter]
addObserver:observer_bridge_
selector:@selector(windowDidChangeOcclusionState:)
name:NSWindowDidDeminiaturizeNotification
object:anchor_window_];
}
void WidgetOwnerNSWindowAdapter::OnWindowWillClose() {
// Retain the child window before closing it. If the last reference to the
// NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
// See e.g. http://crbug.com/616701.
base::scoped_nsobject<NSWindow> child_window(child_->ns_window(),
base::scoped_policy::RETAIN);
// AppKit child window relationships break when the windows are not visible,
// so if the child is not visible, it won't currently be a child.
if (![child_window isVisible])
DCHECK(![child_window parentWindow] && ![child_window sheetParent]);
DCHECK([child_window delegate]);
[child_window close];
// Note: |this| will be deleted here.
DCHECK(![child_window parentWindow]);
DCHECK(![child_window delegate]);
}
void WidgetOwnerNSWindowAdapter::OnWindowDidChangeOcclusionState() {
// The adapter only needs to handle a parent "show", since the only way it
// should be hidden is via -[NSApp hide], and all BridgedNativeWidgets
// subscribe to NSApplicationDidHideNotification already.
if (![anchor_window_ isVisible])
return;
if (child_->window_visible()) {
// A sheet should never have a parentWindow, otherwise dismissing the sheet
// causes graphical glitches (http://crbug.com/605098). Non-sheets should
// always have a parentWindow.
DCHECK([child_->ns_window() isSheet] !=
!![child_->ns_window() parentWindow]);
DCHECK(child_->wants_to_be_visible());
return;
}
// The parent relationship should have been removed when the child was hidden.
DCHECK(![child_->ns_window() parentWindow]);
if (!child_->wants_to_be_visible())
return;
[child_->ns_window() orderWindow:NSWindowAbove
relativeTo:[anchor_window_ windowNumber]];
// Ordering the window should add back the relationship (unless it's a sheet).
DCHECK([child_->ns_window() isSheet] != !![child_->ns_window() parentWindow]);
DCHECK(child_->window_visible());
}
NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() {
return anchor_window_;
}
gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const {
NSRect rect_in_window =
[anchor_view_ convertRect:[anchor_view_ bounds] toView:nil];
NSRect rect_in_screen = [anchor_window_ convertRectToScreen:rect_in_window];
// Ensure we anchor off the top-left of |anchor_view_| (rect_in_screen.origin
// is the bottom-left of the view).
NSPoint anchor_in_screen =
NSMakePoint(NSMinX(rect_in_screen), NSMaxY(rect_in_screen));
return gfx::ScreenPointFromNSPoint(anchor_in_screen).OffsetFromOrigin();
}
bool WidgetOwnerNSWindowAdapter::IsVisibleParent() const {
return [anchor_window_ isVisible];
}
void WidgetOwnerNSWindowAdapter::RemoveChildWindow(
BridgedNativeWidgetImpl* child) {
DCHECK_EQ(child, child_);
[GetNSWindow() removeChildWindow:child->ns_window()];
delete this;
}
WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() {
[[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_];
}
} // namespace views
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment