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

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

Issue 1063933003: MacViews: Allow views::Widgets to be parented off NSWindows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@20150401-MacViews-AppInfo-Standalone
Patch Set: fix gyp Created 5 years, 7 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
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().

Powered by Google App Engine
This is Rietveld 408576698