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(). |