Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" | 5 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/mac/sdk_forward_declarations.h" | 10 #include "base/mac/sdk_forward_declarations.h" |
| 11 #include "ui/gfx/geometry/rect.h" | 11 #include "ui/gfx/geometry/rect.h" |
| 12 #include "ui/gfx/geometry/vector2d.h" | 12 #include "ui/gfx/geometry/vector2d.h" |
| 13 #import "ui/gfx/mac/coordinate_conversion.h" | 13 #import "ui/gfx/mac/coordinate_conversion.h" |
| 14 #import "ui/views/cocoa/bridged_native_widget.h" | 14 #import "ui/views/cocoa/bridged_native_widget.h" |
| 15 | 15 |
| 16 // Bridges an AppKit observer to observe when the (non-views) NSWindow owning a | 16 // Bridges an AppKit observer to observe when the (non-views) NSWindow owning a |
| 17 // views::Widget will close. | 17 // views::Widget will close. |
|
karandeepb
2016/10/27 03:21:17
Modify this comment. It's also observing changes t
tapted
2016/10/27 04:06:48
Done.
| |
| 18 @interface WidgetOwnerNSWindowAdapterBridge : NSObject { | 18 @interface WidgetOwnerNSWindowAdapterBridge : NSObject { |
| 19 @private | 19 @private |
| 20 views::WidgetOwnerNSWindowAdapter* adapter_; // Weak. Owns us. | 20 views::WidgetOwnerNSWindowAdapter* adapter_; // Weak. Owns us. |
| 21 } | 21 } |
| 22 - (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter; | 22 - (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter; |
| 23 - (void)windowWillClose:(NSNotification*)notification; | 23 - (void)windowWillClose:(NSNotification*)notification; |
| 24 - (void)windowDidChangeOcclusionState:(NSNotification*)notification; | |
| 24 @end | 25 @end |
| 25 | 26 |
| 26 @implementation WidgetOwnerNSWindowAdapterBridge | 27 @implementation WidgetOwnerNSWindowAdapterBridge |
| 27 | 28 |
| 28 - (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter { | 29 - (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter { |
| 29 if ((self = [super init])) | 30 if ((self = [super init])) |
| 30 adapter_ = adapter; | 31 adapter_ = adapter; |
| 31 return self; | 32 return self; |
| 32 } | 33 } |
| 33 | 34 |
| 34 - (void)windowWillClose:(NSNotification*)notification { | 35 - (void)windowWillClose:(NSNotification*)notification { |
| 35 adapter_->OnWindowWillClose(); | 36 adapter_->OnWindowWillClose(); |
| 36 } | 37 } |
| 37 | 38 |
| 39 - (void)windowDidChangeOcclusionState:(NSNotification*)notification { | |
| 40 adapter_->OnWindowDidChangeOcclusionState(); | |
| 41 } | |
| 42 | |
| 38 @end | 43 @end |
| 39 | 44 |
| 40 namespace views { | 45 namespace views { |
| 41 | 46 |
| 42 WidgetOwnerNSWindowAdapter::WidgetOwnerNSWindowAdapter( | 47 WidgetOwnerNSWindowAdapter::WidgetOwnerNSWindowAdapter( |
| 43 BridgedNativeWidget* child, | 48 BridgedNativeWidget* child, |
| 44 NSView* anchor_view) | 49 NSView* anchor_view) |
| 45 : child_(child), | 50 : child_(child), |
| 46 anchor_view_([anchor_view retain]), | 51 anchor_view_([anchor_view retain]), |
| 47 observer_bridge_( | 52 observer_bridge_( |
| 48 [[WidgetOwnerNSWindowAdapterBridge alloc] initWithAdapter:this]) { | 53 [[WidgetOwnerNSWindowAdapterBridge alloc] initWithAdapter:this]) { |
| 49 | 54 |
| 50 // Although the |anchor_view| must be in an NSWindow when the child dialog is | 55 // Although the |anchor_view| must be in an NSWindow when the child dialog is |
| 51 // created, it's permitted for the |anchor_view| to be removed from its view | 56 // created, it's permitted for the |anchor_view| to be removed from its view |
| 52 // hierarchy before the child dialog window is fully removed from screen. When | 57 // hierarchy before the child dialog window is fully removed from screen. When |
| 53 // this happens, [anchor_view_ window] will become nil, so retain both. | 58 // this happens, [anchor_view_ window] will become nil, so retain both. |
| 54 anchor_window_.reset([[anchor_view_ window] retain]); | 59 anchor_window_.reset([[anchor_view_ window] retain]); |
| 55 DCHECK(anchor_window_); | 60 DCHECK(anchor_window_); |
| 56 | 61 |
| 57 [[NSNotificationCenter defaultCenter] | 62 [[NSNotificationCenter defaultCenter] |
| 58 addObserver:observer_bridge_ | 63 addObserver:observer_bridge_ |
| 59 selector:@selector(windowWillClose:) | 64 selector:@selector(windowWillClose:) |
| 60 name:NSWindowWillCloseNotification | 65 name:NSWindowWillCloseNotification |
| 61 object:anchor_window_]; | 66 object:anchor_window_]; |
| 67 | |
| 68 [[NSNotificationCenter defaultCenter] | |
|
karandeepb
2016/10/27 03:21:17
Maybe add a comment explaining why we need to obse
tapted
2016/10/27 04:06:48
Done.
| |
| 69 addObserver:observer_bridge_ | |
| 70 selector:@selector(windowDidChangeOcclusionState:) | |
| 71 name:NSWindowDidChangeOcclusionStateNotification | |
| 72 object:anchor_window_]; | |
| 62 } | 73 } |
| 63 | 74 |
| 64 void WidgetOwnerNSWindowAdapter::OnWindowWillClose() { | 75 void WidgetOwnerNSWindowAdapter::OnWindowWillClose() { |
| 65 // Retain the child window before closing it. If the last reference to the | 76 // Retain the child window before closing it. If the last reference to the |
| 66 // NSWindow goes away inside -[NSWindow close], then bad stuff can happen. | 77 // NSWindow goes away inside -[NSWindow close], then bad stuff can happen. |
| 67 // See e.g. http://crbug.com/616701. | 78 // See e.g. http://crbug.com/616701. |
| 68 base::scoped_nsobject<NSWindow> child_window(child_->ns_window(), | 79 base::scoped_nsobject<NSWindow> child_window(child_->ns_window(), |
| 69 base::scoped_policy::RETAIN); | 80 base::scoped_policy::RETAIN); |
| 70 | 81 |
| 71 // AppKit child window relationships break when the windows are not visible, | 82 // AppKit child window relationships break when the windows are not visible, |
| 72 // so if the child is not visible, it won't currently be a child. | 83 // so if the child is not visible, it won't currently be a child. |
| 73 DCHECK(![child_window isVisible] || [child_window parentWindow]); | 84 DCHECK(![child_window isVisible] || [child_window parentWindow]); |
| 74 DCHECK([child_window delegate]); | 85 DCHECK([child_window delegate]); |
| 75 | 86 |
| 76 [child_window close]; | 87 [child_window close]; |
| 77 // Note: |this| will be deleted here. | 88 // Note: |this| will be deleted here. |
| 78 | 89 |
| 79 DCHECK(![child_window parentWindow]); | 90 DCHECK(![child_window parentWindow]); |
| 80 DCHECK(![child_window delegate]); | 91 DCHECK(![child_window delegate]); |
| 81 } | 92 } |
| 82 | 93 |
| 94 void WidgetOwnerNSWindowAdapter::OnWindowDidChangeOcclusionState() { | |
| 95 // The adapter only needs to handle a parent "show", since the only way it | |
| 96 // should be hidden is via -[NSApp hide], and all BridgedNativeWidgets | |
| 97 // subscribe to NSApplicationDidHideNotification already. | |
| 98 if (![anchor_window_ isVisible]) | |
|
karandeepb
2016/10/27 03:21:17
Just to clarify, the parent-child relationship bre
tapted
2016/10/27 04:06:48
Yup. AppKit fails to update zorder/position for ch
| |
| 99 return; | |
| 100 | |
| 101 if (child_->window_visible()) { | |
| 102 DCHECK(child_->wants_to_be_visible()); | |
|
karandeepb
2016/10/27 03:21:17
Should we DCHECK([child->ns_window() parentWindow]
tapted
2016/10/27 04:06:48
Done.
| |
| 103 return; | |
| 104 } | |
| 105 | |
| 106 if (!child_->wants_to_be_visible()) | |
| 107 return; | |
| 108 | |
|
karandeepb
2016/10/27 03:21:17
So now the parent is visible, and the child is hid
tapted
2016/10/27 04:06:48
I don't think this is the same. The parent window
| |
| 109 // The parent relationship should have been removed when the child was hidden. | |
| 110 DCHECK(![child_->ns_window() parentWindow]); | |
|
karandeepb
2016/10/27 03:21:17
Can this DCHECK move before the preceding if condi
tapted
2016/10/27 04:06:48
Done.
| |
| 111 [child_->ns_window() orderWindow:NSWindowAbove | |
| 112 relativeTo:[anchor_window_ windowNumber]]; | |
| 113 | |
| 114 // Ordering the window should add back the relationship. | |
| 115 DCHECK([child_->ns_window() parentWindow]); | |
|
karandeepb
2016/10/27 03:21:17
DCHECK(child_->window_visible())?
tapted
2016/10/27 04:06:48
Done.
| |
| 116 } | |
| 117 | |
| 83 NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() { | 118 NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() { |
| 84 return anchor_window_; | 119 return anchor_window_; |
| 85 } | 120 } |
| 86 | 121 |
| 87 gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const { | 122 gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const { |
| 88 NSRect rect_in_window = | 123 NSRect rect_in_window = |
| 89 [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil]; | 124 [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil]; |
| 90 NSRect rect_in_screen = [anchor_window_ convertRectToScreen:rect_in_window]; | 125 NSRect rect_in_screen = [anchor_window_ convertRectToScreen:rect_in_window]; |
| 91 // Ensure we anchor off the top-left of |anchor_view_| (rect_in_screen.origin | 126 // Ensure we anchor off the top-left of |anchor_view_| (rect_in_screen.origin |
| 92 // is the bottom-left of the view). | 127 // is the bottom-left of the view). |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 103 DCHECK_EQ(child, child_); | 138 DCHECK_EQ(child, child_); |
| 104 [GetNSWindow() removeChildWindow:child->ns_window()]; | 139 [GetNSWindow() removeChildWindow:child->ns_window()]; |
| 105 delete this; | 140 delete this; |
| 106 } | 141 } |
| 107 | 142 |
| 108 WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() { | 143 WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() { |
| 109 [[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_]; | 144 [[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_]; |
| 110 } | 145 } |
| 111 | 146 |
| 112 } // namespace views | 147 } // namespace views |
| OLD | NEW |