Chromium Code Reviews| 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 24275787c04e43ac1ab87b032e13ff5f4665461c..47005d179a00d276cd695af1e749076a52fd34ba 100644 |
| --- a/ui/views/cocoa/bridged_native_widget.mm |
| +++ b/ui/views/cocoa/bridged_native_widget.mm |
| @@ -21,6 +21,7 @@ |
| #import "ui/views/cocoa/cocoa_mouse_capture.h" |
| #import "ui/views/cocoa/bridged_content_view.h" |
| #import "ui/views/cocoa/views_nswindow_delegate.h" |
| +#import "ui/views/cocoa/widget_owner_nswindow_adapter.h" |
| #include "ui/views/widget/native_widget_mac.h" |
| #include "ui/views/ime/input_method_bridge.h" |
| #include "ui/views/ime/null_input_method.h" |
| @@ -155,14 +156,17 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, |
| if (params.parent) { |
| // Disallow creating child windows of views not currently in an NSWindow. |
| CHECK([params.parent window]); |
| - BridgedNativeWidget* parent = |
| + BridgedNativeWidget* bridged_native_widget_parent = |
| NativeWidgetMac::GetBridgeForNativeWindow([params.parent window]); |
| - // The parent could be an NSWindow without an associated Widget. That could |
| - // work by observing NSWindowWillCloseNotification, but for now it's not |
| - // supported, and there might not be a use-case for that. |
| - CHECK(parent); |
| - parent_ = parent; |
| - parent->child_windows_.push_back(this); |
| + // If the parent is another BridgedNativeWidget, just add to the collection |
| + // of child windows it owns and manages. Otherwise, create an adapter to |
| + // anchor the child widget and observe when the parent NSWindow is closed. |
| + if (bridged_native_widget_parent) { |
| + parent_ = bridged_native_widget_parent; |
| + bridged_native_widget_parent->child_windows_.push_back(this); |
| + } else { |
| + parent_ = new WidgetOwnerNSWindowAdapter(this, params.parent); |
| + } |
| } |
| // Set a meaningful initial bounds. Note that except for frameless widgets |
| @@ -233,7 +237,7 @@ void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { |
| GetWindowSizeForClientSize(window_, clamped_content_size)); |
| if (parent_ && !PositionWindowInScreenCoordinates(widget, widget_type_)) |
| - actual_new_bounds.Offset(parent_->GetRestoredBounds().OffsetFromOrigin()); |
| + actual_new_bounds.Offset(parent_->ChildWindowOffset()); |
| [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds) |
| display:YES |
| @@ -278,17 +282,13 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) { |
| } |
| DCHECK(wants_to_be_visible_); |
| - |
| - // If there's a hidden ancestor, return and wait for it to become visible. |
| - for (BridgedNativeWidget* ancestor = parent(); |
| - ancestor; |
| - ancestor = ancestor->parent()) { |
| - if (!ancestor->window_visible_) |
| - return; |
| - } |
| + // If the parent (or an ancestor) is hidden, return and wait for it to become |
| + // visible. |
| + if (parent() && !parent()->IsVisibleParent()) |
| + return; |
| if (native_widget_mac_->GetWidget()->IsModal()) { |
| - NSWindow* parent_window = parent_->ns_window(); |
| + NSWindow* parent_window = parent_->GetNSWindow(); |
| DCHECK(parent_window); |
| [NSApp beginSheet:window_ |
| @@ -308,7 +308,7 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) { |
| // will order above all windows at the same level. |
| NSInteger parent_window_number = 0; |
| if (parent()) |
| - parent_window_number = [parent()->ns_window() windowNumber]; |
| + parent_window_number = [parent()->GetNSWindow() windowNumber]; |
| [window_ orderWindow:NSWindowAbove |
| relativeTo:parent_window_number]; |
| @@ -361,8 +361,10 @@ void BridgedNativeWidget::SetCursor(NSCursor* cursor) { |
| } |
| void BridgedNativeWidget::OnWindowWillClose() { |
| - if (parent_) |
| + if (parent_) { |
| parent_->RemoveChildWindow(this); |
| + parent_ = nullptr; |
| + } |
| [window_ setDelegate:nil]; |
| [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
| native_widget_mac_->OnWindowWillClose(); |
| @@ -464,7 +466,7 @@ void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
| wants_to_be_visible_ = true; |
| if (parent_) |
| - [parent_->ns_window() addChildWindow:window_ ordered:NSWindowAbove]; |
| + [parent_->GetNSWindow() addChildWindow:window_ ordered:NSWindowAbove]; |
| } else { |
| mouse_capture_.reset(); // Capture on hidden windows is not permitted. |
| @@ -472,7 +474,7 @@ void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
| // list. Cocoa's childWindow management breaks down when child windows are |
| // hidden. |
| if (parent_) |
| - [parent_->ns_window() removeChildWindow:window_]; |
| + [parent_->GetNSWindow() removeChildWindow:window_]; |
| } |
| // TODO(tapted): Investigate whether we want this for Mac. This is what Aura |
| @@ -664,18 +666,21 @@ void BridgedNativeWidget::AcceleratedWidgetHitError() { |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| -// BridgedNativeWidget, private: |
| +// BridgedNativeWidget, BridgedNativeWidgetOwner: |
| -void BridgedNativeWidget::RemoveOrDestroyChildren() { |
| - // TODO(tapted): Implement unowned child windows if required. |
| - while (!child_windows_.empty()) { |
| - // The NSWindow can only be destroyed after -[NSWindow close] is complete. |
| - // Retain the window, otherwise the reference count can reach zero when the |
| - // child calls back into RemoveChildWindow() via its OnWindowWillClose(). |
| - base::scoped_nsobject<NSWindow> child( |
| - [child_windows_.back()->ns_window() retain]); |
| - [child close]; |
| - } |
| +NSWindow* BridgedNativeWidget::GetNSWindow() { |
| + return window_; |
| +} |
| + |
| +gfx::Vector2d BridgedNativeWidget::ChildWindowOffset() { |
| + return gfx::ScreenRectFromNSRect([window_ frame]).OffsetFromOrigin(); |
| +} |
| + |
| +bool BridgedNativeWidget::IsVisibleParent() { |
| + // If there's a hidden ancestor, IsVisible() returns false regardless. |
| + if (!window_visible_ || !parent()) |
| + return window_visible_; |
| + return parent()->IsVisibleParent(); |
|
Andre
2015/05/07 17:32:37
How about,
return parent() ? parent()->IsVisible
tapted
2015/05/07 23:43:50
Done (also put the recursive call after the sequen
|
| } |
| void BridgedNativeWidget::RemoveChildWindow(BridgedNativeWidget* child) { |
| @@ -683,7 +688,6 @@ void BridgedNativeWidget::RemoveChildWindow(BridgedNativeWidget* child) { |
| child_windows_.begin(), child_windows_.end(), child); |
| DCHECK(location != child_windows_.end()); |
| child_windows_.erase(location); |
| - child->parent_ = nullptr; |
| // Note the child is sometimes removed already by AppKit. This depends on OS |
| // version, and possibly some unpredictable reference counting. Removing it |
| @@ -691,6 +695,21 @@ void BridgedNativeWidget::RemoveChildWindow(BridgedNativeWidget* child) { |
| [window_ removeChildWindow:child->window_]; |
| } |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// BridgedNativeWidget, private: |
| + |
| +void BridgedNativeWidget::RemoveOrDestroyChildren() { |
| + // TODO(tapted): Implement unowned child windows if required. |
| + while (!child_windows_.empty()) { |
| + // The NSWindow can only be destroyed after -[NSWindow close] is complete. |
| + // Retain the window, otherwise the reference count can reach zero when the |
| + // child calls back into RemoveChildWindow() via its OnWindowWillClose(). |
| + base::scoped_nsobject<NSWindow> child( |
| + [child_windows_.back()->ns_window() retain]); |
| + [child close]; |
| + } |
| +} |
| + |
| void BridgedNativeWidget::NotifyVisibilityChangeDown() { |
| // Child windows sometimes like to close themselves in response to visibility |
| // changes. That's supported, but only with the asynchronous Widget::Close(). |