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

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: respond to comments 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 or change occlusion state.
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 // BridgedNativeWidget removes NSWindow parent/child relationships for hidden
69 // windows. Observe when the parent's visibility changes so they can be
70 // reconnected.
71 [[NSNotificationCenter defaultCenter]
72 addObserver:observer_bridge_
73 selector:@selector(windowDidChangeOcclusionState:)
74 name:NSWindowDidChangeOcclusionStateNotification
75 object:anchor_window_];
62 } 76 }
63 77
64 void WidgetOwnerNSWindowAdapter::OnWindowWillClose() { 78 void WidgetOwnerNSWindowAdapter::OnWindowWillClose() {
65 // Retain the child window before closing it. If the last reference to the 79 // 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. 80 // NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
67 // See e.g. http://crbug.com/616701. 81 // See e.g. http://crbug.com/616701.
68 base::scoped_nsobject<NSWindow> child_window(child_->ns_window(), 82 base::scoped_nsobject<NSWindow> child_window(child_->ns_window(),
69 base::scoped_policy::RETAIN); 83 base::scoped_policy::RETAIN);
70 84
71 // AppKit child window relationships break when the windows are not visible, 85 // 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. 86 // so if the child is not visible, it won't currently be a child.
73 DCHECK(![child_window isVisible] || [child_window parentWindow]); 87 DCHECK(![child_window isVisible] || [child_window parentWindow]);
74 DCHECK([child_window delegate]); 88 DCHECK([child_window delegate]);
75 89
76 [child_window close]; 90 [child_window close];
77 // Note: |this| will be deleted here. 91 // Note: |this| will be deleted here.
78 92
79 DCHECK(![child_window parentWindow]); 93 DCHECK(![child_window parentWindow]);
80 DCHECK(![child_window delegate]); 94 DCHECK(![child_window delegate]);
81 } 95 }
82 96
97 void WidgetOwnerNSWindowAdapter::OnWindowDidChangeOcclusionState() {
98 // The adapter only needs to handle a parent "show", since the only way it
99 // should be hidden is via -[NSApp hide], and all BridgedNativeWidgets
100 // subscribe to NSApplicationDidHideNotification already.
101 if (![anchor_window_ isVisible])
102 return;
103
104 if (child_->window_visible()) {
105 DCHECK([child_->ns_window() parentWindow]);
106 DCHECK(child_->wants_to_be_visible());
107 return;
108 }
109
110 // The parent relationship should have been removed when the child was hidden.
111 DCHECK(![child_->ns_window() parentWindow]);
112 if (!child_->wants_to_be_visible())
113 return;
114
115 [child_->ns_window() orderWindow:NSWindowAbove
116 relativeTo:[anchor_window_ windowNumber]];
117
118 // Ordering the window should add back the relationship.
119 DCHECK([child_->ns_window() parentWindow]);
120 DCHECK(child_->window_visible());
121 }
122
83 NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() { 123 NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() {
84 return anchor_window_; 124 return anchor_window_;
85 } 125 }
86 126
87 gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const { 127 gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const {
88 NSRect rect_in_window = 128 NSRect rect_in_window =
89 [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil]; 129 [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil];
90 NSRect rect_in_screen = [anchor_window_ convertRectToScreen:rect_in_window]; 130 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 131 // Ensure we anchor off the top-left of |anchor_view_| (rect_in_screen.origin
92 // is the bottom-left of the view). 132 // is the bottom-left of the view).
(...skipping 10 matching lines...) Expand all
103 DCHECK_EQ(child, child_); 143 DCHECK_EQ(child, child_);
104 [GetNSWindow() removeChildWindow:child->ns_window()]; 144 [GetNSWindow() removeChildWindow:child->ns_window()];
105 delete this; 145 delete this;
106 } 146 }
107 147
108 WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() { 148 WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() {
109 [[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_]; 149 [[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_];
110 } 150 }
111 151
112 } // namespace views 152 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/cocoa/widget_owner_nswindow_adapter.h ('k') | ui/views/widget/native_widget_mac_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698