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

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

Issue 831643004: MacViews: Fix child window z-order and SetBounds (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix typo: than->that Created 5 years, 11 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 unified diff | Download patch
« no previous file with comments | « no previous file | ui/views/test/widget_test.h » ('j') | ui/views/test/widget_test_aura.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/bridged_native_widget.h" 5 #import "ui/views/cocoa/bridged_native_widget.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/mac/mac_util.h" 8 #include "base/mac/mac_util.h"
9 #import "base/mac/sdk_forward_declarations.h" 9 #import "base/mac/sdk_forward_declarations.h"
10 #include "base/thread_task_runner_handle.h" 10 #include "base/thread_task_runner_handle.h"
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 if (focus_manager_) 114 if (focus_manager_)
115 focus_manager_->RemoveFocusChangeListener(this); 115 focus_manager_->RemoveFocusChangeListener(this);
116 116
117 if (focus_manager) 117 if (focus_manager)
118 focus_manager->AddFocusChangeListener(this); 118 focus_manager->AddFocusChangeListener(this);
119 119
120 focus_manager_ = focus_manager; 120 focus_manager_ = focus_manager;
121 } 121 }
122 122
123 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { 123 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
124 [window_ setFrame:gfx::ScreenRectToNSRect(new_bounds) 124 gfx::Rect actual_new_bounds(new_bounds);
125 if (parent_)
126 actual_new_bounds.Offset(parent_->GetRestoredBounds().OffsetFromOrigin());
127
128 [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds)
125 display:YES 129 display:YES
126 animate:NO]; 130 animate:NO];
127 } 131 }
128 132
129 void BridgedNativeWidget::SetRootView(views::View* view) { 133 void BridgedNativeWidget::SetRootView(views::View* view) {
130 if (view == [bridged_view_ hostedView]) 134 if (view == [bridged_view_ hostedView])
131 return; 135 return;
132 136
133 // If this is ever false, the compositor will need to be properly torn down 137 // If this is ever false, the compositor will need to be properly torn down
134 // and replaced, pointing at the new view. 138 // and replaced, pointing at the new view.
(...skipping 18 matching lines...) Expand all
153 // Ensure that: 157 // Ensure that:
154 // - A window with an invisible parent is not made visible. 158 // - A window with an invisible parent is not made visible.
155 // - A parent changing visibility updates child window visibility. 159 // - A parent changing visibility updates child window visibility.
156 // * But only when changed via this function - ignore changes via the 160 // * But only when changed via this function - ignore changes via the
157 // NSWindow API, or changes propagating out from here. 161 // NSWindow API, or changes propagating out from here.
158 wants_to_be_visible_ = new_state != HIDE_WINDOW; 162 wants_to_be_visible_ = new_state != HIDE_WINDOW;
159 163
160 if (new_state == HIDE_WINDOW) { 164 if (new_state == HIDE_WINDOW) {
161 [window_ orderOut:nil]; 165 [window_ orderOut:nil];
162 DCHECK(!window_visible_); 166 DCHECK(!window_visible_);
163 NotifyVisibilityChangeDown();
164 return; 167 return;
165 } 168 }
166 169
167 DCHECK(wants_to_be_visible_); 170 DCHECK(wants_to_be_visible_);
168 171
169 // If there's a hidden ancestor, return and wait for it to become visible. 172 // If there's a hidden ancestor, return and wait for it to become visible.
170 for (BridgedNativeWidget* ancestor = parent(); 173 for (BridgedNativeWidget* ancestor = parent();
171 ancestor; 174 ancestor;
172 ancestor = ancestor->parent()) { 175 ancestor = ancestor->parent()) {
173 if (!ancestor->window_visible_) 176 if (!ancestor->window_visible_)
174 return; 177 return;
175 } 178 }
176 179
177 if (new_state == SHOW_AND_ACTIVATE_WINDOW) { 180 if (new_state == SHOW_AND_ACTIVATE_WINDOW) {
178 [window_ makeKeyAndOrderFront:nil]; 181 [window_ makeKeyAndOrderFront:nil];
179 [NSApp activateIgnoringOtherApps:YES]; 182 [NSApp activateIgnoringOtherApps:YES];
180 } else { 183 } else {
181 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a 184 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a
182 // parent window. So, if there's a parent, order above that. Otherwise, this 185 // parent window. So, if there's a parent, order above that. Otherwise, this
183 // will order above all windows at the same level. 186 // will order above all windows at the same level.
184 NSInteger parent_window_number = 0; 187 NSInteger parent_window_number = 0;
185 if (parent()) 188 if (parent())
186 parent_window_number = [parent()->ns_window() windowNumber]; 189 parent_window_number = [parent()->ns_window() windowNumber];
187 190
188 [window_ orderWindow:NSWindowAbove 191 [window_ orderWindow:NSWindowAbove
189 relativeTo:parent_window_number]; 192 relativeTo:parent_window_number];
190 } 193 }
191 DCHECK(window_visible_); 194 DCHECK(window_visible_);
192 NotifyVisibilityChangeDown();
193 } 195 }
194 196
195 void BridgedNativeWidget::AcquireCapture() { 197 void BridgedNativeWidget::AcquireCapture() {
196 DCHECK(!HasCapture()); 198 DCHECK(!HasCapture());
197 if (!window_visible_) 199 if (!window_visible_)
198 return; // Capture on hidden windows is disallowed. 200 return; // Capture on hidden windows is disallowed.
199 201
200 mouse_capture_.reset(new CocoaMouseCapture(this)); 202 mouse_capture_.reset(new CocoaMouseCapture(this));
201 } 203 }
202 204
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { 303 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) {
302 if (window_visible_ == new_visibility) 304 if (window_visible_ == new_visibility)
303 return; 305 return;
304 306
305 window_visible_ = new_visibility; 307 window_visible_ = new_visibility;
306 308
307 // If arriving via SetVisible(), |wants_to_be_visible_| should already be set. 309 // If arriving via SetVisible(), |wants_to_be_visible_| should already be set.
308 // If made visible externally (e.g. Cmd+H), just roll with it. Don't try (yet) 310 // If made visible externally (e.g. Cmd+H), just roll with it. Don't try (yet)
309 // to distinguish being *hidden* externally from being hidden by a parent 311 // to distinguish being *hidden* externally from being hidden by a parent
310 // window - we might not need that. 312 // window - we might not need that.
311 if (window_visible_) 313 if (window_visible_) {
312 wants_to_be_visible_ = true; 314 wants_to_be_visible_ = true;
313 315
314 // Capture on hidden windows is not permitted. 316 if (parent_)
315 if (!window_visible_) 317 [parent_->ns_window() addChildWindow:window_ ordered:NSWindowAbove];
316 mouse_capture_.reset(); 318 } else {
319 mouse_capture_.reset(); // Capture on hidden windows is not permitted.
320
321 // When becoming invisible, remove the entry in any parent's childWindow
322 // list. Cocoa's childWindow management breaks down when child windows are
323 // hidden.
324 if (parent_)
325 [parent_->ns_window() removeChildWindow:window_];
326 }
317 327
318 // TODO(tapted): Investigate whether we want this for Mac. This is what Aura 328 // TODO(tapted): Investigate whether we want this for Mac. This is what Aura
319 // does, and it is what tests expect. However, because layer drawing is 329 // does, and it is what tests expect. However, because layer drawing is
320 // asynchronous (and things like deminiaturize in AppKit are not), it can 330 // asynchronous (and things like deminiaturize in AppKit are not), it can
321 // result in a CALayer appearing on screen before it has been redrawn in the 331 // result in a CALayer appearing on screen before it has been redrawn in the
322 // GPU process. This is a general problem. In content, a helper class, 332 // GPU process. This is a general problem. In content, a helper class,
323 // RenderWidgetResizeHelper, blocks the UI thread in -[NSView setFrameSize:] 333 // RenderWidgetResizeHelper, blocks the UI thread in -[NSView setFrameSize:]
324 // and RenderWidgetHostView::Show() until a frame is ready. 334 // and RenderWidgetHostView::Show() until a frame is ready.
325 if (layer()) { 335 if (layer()) {
326 layer()->SetVisible(window_visible_); 336 layer()->SetVisible(window_visible_);
327 layer()->SchedulePaint(gfx::Rect(GetClientAreaSize())); 337 layer()->SchedulePaint(gfx::Rect(GetClientAreaSize()));
328 } 338 }
329 339
340 NotifyVisibilityChangeDown();
341
330 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged( 342 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
331 window_visible_); 343 window_visible_);
332 344
333 // Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking 345 // Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking
334 // for an "empty" draw, disable auto-display while hidden. For example, this 346 // for an "empty" draw, disable auto-display while hidden. For example, this
335 // prevents Cocoa drawing just *after* a minimize, resulting in a blank window 347 // prevents Cocoa drawing just *after* a minimize, resulting in a blank window
336 // represented in the deminiaturize animation. 348 // represented in the deminiaturize animation.
337 [window_ setAutodisplay:window_visible_]; 349 [window_ setAutodisplay:window_visible_];
338 } 350 }
339 351
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 child->parent_ = nullptr; 505 child->parent_ = nullptr;
494 } 506 }
495 507
496 void BridgedNativeWidget::NotifyVisibilityChangeDown() { 508 void BridgedNativeWidget::NotifyVisibilityChangeDown() {
497 // Child windows sometimes like to close themselves in response to visibility 509 // Child windows sometimes like to close themselves in response to visibility
498 // changes. That's supported, but only with the asynchronous Widget::Close(). 510 // changes. That's supported, but only with the asynchronous Widget::Close().
499 // Perform a heuristic to detect child removal that would break these loops. 511 // Perform a heuristic to detect child removal that would break these loops.
500 const size_t child_count = child_windows_.size(); 512 const size_t child_count = child_windows_.size();
501 if (!window_visible_) { 513 if (!window_visible_) {
502 for (BridgedNativeWidget* child : child_windows_) { 514 for (BridgedNativeWidget* child : child_windows_) {
503 if (child->window_visible_) { 515 if (child->window_visible_)
504 [child->ns_window() orderOut:nil]; 516 [child->ns_window() orderOut:nil];
505 child->NotifyVisibilityChangeDown(); 517
506 CHECK_EQ(child_count, child_windows_.size()); 518 DCHECK(!child->window_visible_);
507 } 519 CHECK_EQ(child_count, child_windows_.size());
508 } 520 }
521 // The orderOut calls above should result in a call to OnVisibilityChanged()
522 // in each child. There, children will remove themselves from the NSWindow
523 // childWindow list as well as propagate NotifyVisibilityChangeDown() calls
524 // to any children of their own.
525 DCHECK_EQ(0u, [[window_ childWindows] count]);
509 return; 526 return;
510 } 527 }
511 528
529 NSUInteger visible_children = 0; // For a DCHECK below.
512 NSInteger parent_window_number = [window_ windowNumber]; 530 NSInteger parent_window_number = [window_ windowNumber];
513 for (BridgedNativeWidget* child: child_windows_) { 531 for (BridgedNativeWidget* child: child_windows_) {
514 // Note: order the child windows on top, regardless of whether or not they 532 // Note: order the child windows on top, regardless of whether or not they
515 // are currently visible. They probably aren't, since the parent was hidden 533 // are currently visible. They probably aren't, since the parent was hidden
516 // prior to this, but they could have been made visible in other ways. 534 // prior to this, but they could have been made visible in other ways.
517 if (child->wants_to_be_visible_) { 535 if (child->wants_to_be_visible_) {
536 ++visible_children;
537 // Here -[NSWindow orderWindow:relativeTo:] is used to put the window on
538 // screen. However, that by itself is insufficient to guarantee a correct
539 // z-order relationship. If this function is being called from a z-order
540 // change in the parent, orderWindow turns out to be unreliable (i.e. the
541 // ordering doesn't always take effect). What this actually relies on is
542 // the resulting call to OnVisibilityChanged() in the child, which will
543 // then insert itself into -[NSWindow childWindows] to let Cocoa do its
544 // internal layering magic.
518 [child->ns_window() orderWindow:NSWindowAbove 545 [child->ns_window() orderWindow:NSWindowAbove
519 relativeTo:parent_window_number]; 546 relativeTo:parent_window_number];
520 child->NotifyVisibilityChangeDown(); 547 DCHECK(child->window_visible_);
521 CHECK_EQ(child_count, child_windows_.size());
522 } 548 }
549 CHECK_EQ(child_count, child_windows_.size());
523 } 550 }
551 DCHECK_EQ(visible_children, [[window_ childWindows] count]);
524 } 552 }
525 553
526 gfx::Size BridgedNativeWidget::GetClientAreaSize() const { 554 gfx::Size BridgedNativeWidget::GetClientAreaSize() const {
527 NSRect content_rect = [window_ contentRectForFrameRect:[window_ frame]]; 555 NSRect content_rect = [window_ contentRectForFrameRect:[window_ frame]];
528 return gfx::Size(NSWidth(content_rect), NSHeight(content_rect)); 556 return gfx::Size(NSWidth(content_rect), NSHeight(content_rect));
529 } 557 }
530 558
531 void BridgedNativeWidget::CreateCompositor() { 559 void BridgedNativeWidget::CreateCompositor() {
532 DCHECK(!compositor_); 560 DCHECK(!compositor_);
533 DCHECK(!compositor_widget_); 561 DCHECK(!compositor_widget_);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 DCHECK(compositor_superview_); 631 DCHECK(compositor_superview_);
604 gfx::Size size_in_dip = GetClientAreaSize(); 632 gfx::Size size_in_dip = GetClientAreaSize();
605 layer()->SetBounds(gfx::Rect(size_in_dip)); 633 layer()->SetBounds(gfx::Rect(size_in_dip));
606 634
607 float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); 635 float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_);
608 compositor_->SetScaleAndSize(scale_factor, 636 compositor_->SetScaleAndSize(scale_factor,
609 ConvertSizeToPixel(scale_factor, size_in_dip)); 637 ConvertSizeToPixel(scale_factor, size_in_dip));
610 } 638 }
611 639
612 } // namespace views 640 } // namespace views
OLDNEW
« no previous file with comments | « no previous file | ui/views/test/widget_test.h » ('j') | ui/views/test/widget_test_aura.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698