| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |