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

Side by Side Diff: ui/views/cocoa/widget_owner_nswindow_adapter.mm

Issue 2448243003: MacViews: Reattach children of native windows when they are exposed. (Closed)
Patch Set: +test Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698