OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "chrome/browser/ui/cocoa/status_bubble_mac.h" | 5 #include "chrome/browser/ui/cocoa/status_bubble_mac.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 changes([NSAnimationContext currentContext]); | 135 changes([NSAnimationContext currentContext]); |
136 // At this point, -animationForKey should have been called by CoreAnimation | 136 // At this point, -animationForKey should have been called by CoreAnimation |
137 // to set up the animation to run. Verify this. | 137 // to set up the animation to run. Verify this. |
138 DCHECK(completionHandler_ == nil); | 138 DCHECK(completionHandler_ == nil); |
139 [NSAnimationContext endGrouping]; | 139 [NSAnimationContext endGrouping]; |
140 } | 140 } |
141 } | 141 } |
142 | 142 |
143 @end | 143 @end |
144 | 144 |
145 // Mac implementation of the status bubble. | |
146 // | |
147 // Child windows interact with Spaces in interesting ways, so this code has to | |
148 // follow these rules: | |
149 // | |
150 // 1) NSWindows cannot have zero size. At times when the status bubble window | |
151 // has no specific size (for example, when hidden), its size is set to | |
152 // ui::kWindowSizeDeterminedLater. | |
153 // | |
154 // 2) Child window frames are in the coordinate space of the screen, not of the | |
155 // parent window. If a child window has its origin at (0, 0), Spaces will | |
156 // position it in the corner of the screen but group it with the parent | |
157 // window in Spaces. This causes Chrome windows to have a large (mostly | |
158 // blank) area in Spaces. To avoid this, child windows always have their | |
159 // origin set to the lower-left corner of the window. | |
160 // | |
161 // 3) Detached child windows may show up as top-level windows in Spaces. To | |
162 // avoid this, once the status bubble is Attach()ed to the parent, it is | |
163 // never detached (except in rare cases when reparenting to a fullscreen | |
164 // window). | |
165 // | |
166 // 4) To avoid unnecessary redraws, if a bubble is in the kBubbleHidden state, | |
167 // its size is always set to ui::kWindowSizeDeterminedLater. The proper | |
168 // width for the current URL or status text is not calculated until the | |
169 // bubble leaves the kBubbleHidden state. | |
170 | |
145 StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate) | 171 StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate) |
146 : parent_(parent), | 172 : parent_(parent), |
147 delegate_(delegate), | 173 delegate_(delegate), |
148 window_(nil), | 174 window_(nil), |
149 status_text_(nil), | 175 status_text_(nil), |
150 url_text_(nil), | 176 url_text_(nil), |
151 state_(kBubbleHidden), | 177 state_(kBubbleHidden), |
152 immediate_(false), | 178 immediate_(false), |
153 is_expanded_(false), | 179 is_expanded_(false), |
154 timer_factory_(this), | 180 timer_factory_(this), |
(...skipping 16 matching lines...) Expand all Loading... | |
171 | 197 |
172 void StatusBubbleMac::SetStatus(const base::string16& status) { | 198 void StatusBubbleMac::SetStatus(const base::string16& status) { |
173 SetText(status, false); | 199 SetText(status, false); |
174 } | 200 } |
175 | 201 |
176 void StatusBubbleMac::SetURL(const GURL& url, const std::string& languages) { | 202 void StatusBubbleMac::SetURL(const GURL& url, const std::string& languages) { |
177 url_ = url; | 203 url_ = url; |
178 languages_ = languages; | 204 languages_ = languages; |
179 | 205 |
180 CGFloat bubble_width = NSWidth([window_ frame]); | 206 CGFloat bubble_width = NSWidth([window_ frame]); |
181 | |
182 // Reset frame size when bubble is hidden. | |
183 if (state_ == kBubbleHidden) { | 207 if (state_ == kBubbleHidden) { |
184 is_expanded_ = false; | 208 DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.width, |
185 NSRect frame = [window_ frame]; | 209 [window_ frame].size.width); |
186 frame.size = ui::kWindowSizeDeterminedLater.size; | 210 DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.height, |
187 [window_ setFrame:frame display:NO]; | 211 [window_ frame].size.height); |
188 bubble_width = NSWidth(CalculateWindowFrame(/*expand=*/false)); | 212 bubble_width = NSWidth(CalculateWindowFrame(/*expand=*/false)); |
189 } | 213 } |
190 | 214 |
191 int text_width = static_cast<int>(bubble_width - | 215 int text_width = static_cast<int>(bubble_width - |
192 kBubbleViewTextPositionX - | 216 kBubbleViewTextPositionX - |
193 kTextPadding); | 217 kTextPadding); |
194 | 218 |
195 // Scale from view to window coordinates before eliding URL string. | 219 // Scale from view to window coordinates before eliding URL string. |
196 NSSize scaled_width = NSMakeSize(text_width, 0); | 220 NSSize scaled_width = NSMakeSize(text_width, 0); |
197 scaled_width = [[parent_ contentView] convertSize:scaled_width fromView:nil]; | 221 scaled_width = [[parent_ contentView] convertSize:scaled_width fromView:nil]; |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
444 [window_ orderFront:nil]; | 468 [window_ orderFront:nil]; |
445 [parent_ addChildWindow:window_ ordered:NSWindowAbove]; | 469 [parent_ addChildWindow:window_ ordered:NSWindowAbove]; |
446 | 470 |
447 [[window_ contentView] setThemeProvider:parent_]; | 471 [[window_ contentView] setThemeProvider:parent_]; |
448 } | 472 } |
449 | 473 |
450 void StatusBubbleMac::Detach() { | 474 void StatusBubbleMac::Detach() { |
451 DCHECK(is_attached()); | 475 DCHECK(is_attached()); |
452 | 476 |
453 // Magic setFrame: See http://crbug.com/58506 and http://crrev.com/3564021 . | 477 // Magic setFrame: See http://crbug.com/58506 and http://crrev.com/3564021 . |
454 [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO]; | 478 // TODO(rohitrao): Does the frame size actually matter here? Can we always |
479 // set it to kWindowSizeDeterminedLater? | |
rohitrao (ping after 24h)
2015/03/03 15:54:00
I think we can probably get away with always using
| |
480 NSRect frame = CalculateWindowFrame(/*expand=*/false); | |
481 if (state_ == kBubbleHidden) { | |
482 frame.size = ui::kWindowSizeDeterminedLater.size; | |
erikchen
2015/03/03 18:19:50
"""
NSRect frame = ui::kWindowSizeDeterminedLater.
rohitrao (ping after 24h)
2015/03/03 18:53:51
Done.
| |
483 } | |
484 [window_ setFrame:frame display:NO]; | |
455 [parent_ removeChildWindow:window_]; // See crbug.com/28107 ... | 485 [parent_ removeChildWindow:window_]; // See crbug.com/28107 ... |
456 [window_ orderOut:nil]; // ... and crbug.com/29054. | 486 [window_ orderOut:nil]; // ... and crbug.com/29054. |
457 | 487 |
458 [[window_ contentView] setThemeProvider:nil]; | 488 [[window_ contentView] setThemeProvider:nil]; |
459 } | 489 } |
460 | 490 |
461 void StatusBubbleMac::AnimationDidStop() { | 491 void StatusBubbleMac::AnimationDidStop() { |
462 DCHECK([NSThread isMainThread]); | 492 DCHECK([NSThread isMainThread]); |
463 DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut); | 493 DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut); |
464 DCHECK(is_attached()); | 494 DCHECK(is_attached()); |
465 | 495 |
466 if (state_ == kBubbleShowingFadeIn) { | 496 if (state_ == kBubbleShowingFadeIn) { |
467 DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity); | 497 DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity); |
468 SetState(kBubbleShown); | 498 SetState(kBubbleShown); |
469 } else { | 499 } else { |
470 DCHECK_EQ([[window_ animator] alphaValue], 0.0); | 500 DCHECK_EQ([[window_ animator] alphaValue], 0.0); |
471 SetState(kBubbleHidden); | 501 SetState(kBubbleHidden); |
472 } | 502 } |
473 } | 503 } |
474 | 504 |
475 void StatusBubbleMac::SetState(StatusBubbleState state) { | 505 void StatusBubbleMac::SetState(StatusBubbleState state) { |
476 if (state == state_) | 506 if (state == state_) |
477 return; | 507 return; |
478 | 508 |
479 if (state == kBubbleHidden) { | 509 if (state == kBubbleHidden) { |
510 is_expanded_ = false; | |
erikchen
2015/03/03 18:19:50
is_expanded_ gets set to false in several location
rohitrao (ping after 24h)
2015/03/03 18:53:51
Agreed. I don't fully understand when it needs to
rohitrao (ping after 24h)
2015/03/03 18:53:51
Agreed. I don't fully understand when it needs to
| |
511 | |
480 // When hidden (with alpha of 0), make the window have the minimum size, | 512 // When hidden (with alpha of 0), make the window have the minimum size, |
481 // while still keeping the same origin. It's important to not set the | 513 // while still keeping the same origin. It's important to not set the |
482 // origin to 0,0 as that will cause the window to use more space in | 514 // origin to 0,0 as that will cause the window to use more space in |
483 // Expose/Mission Control. See http://crbug.com/81969. | 515 // Expose/Mission Control. See http://crbug.com/81969. |
484 // | 516 // |
485 // Also, doing it this way instead of detaching the window avoids bugs with | 517 // Also, doing it this way instead of detaching the window avoids bugs with |
486 // Spaces and Cmd-`. See http://crbug.com/31821 and http://crbug.com/61629. | 518 // Spaces and Cmd-`. See http://crbug.com/31821 and http://crbug.com/61629. |
487 NSRect frame = [window_ frame]; | 519 NSRect frame = [window_ frame]; |
488 frame.size = ui::kWindowSizeDeterminedLater.size; | 520 frame.size = ui::kWindowSizeDeterminedLater.size; |
489 [window_ setFrame:frame display:YES]; | 521 [window_ setFrame:frame display:YES]; |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 [NSAnimationContext beginGrouping]; | 747 [NSAnimationContext beginGrouping]; |
716 [[NSAnimationContext currentContext] setDuration:kExpansionDurationSeconds]; | 748 [[NSAnimationContext currentContext] setDuration:kExpansionDurationSeconds]; |
717 [[window_ animator] setFrame:actual_window_frame display:YES]; | 749 [[window_ animator] setFrame:actual_window_frame display:YES]; |
718 [NSAnimationContext endGrouping]; | 750 [NSAnimationContext endGrouping]; |
719 } | 751 } |
720 | 752 |
721 void StatusBubbleMac::UpdateSizeAndPosition() { | 753 void StatusBubbleMac::UpdateSizeAndPosition() { |
722 if (!window_) | 754 if (!window_) |
723 return; | 755 return; |
724 | 756 |
725 // Hidden bubbles always have size equal to ui::kWindowSizeDeterminedLater. | 757 // There is no need to update the size if the bubble is hidden. |
726 if (state_ == kBubbleHidden) { | 758 if (state_ == kBubbleHidden) { |
727 NSRect frame = [window_ frame]; | 759 // Verify that hidden bubbles always have size equal to |
728 frame.size = ui::kWindowSizeDeterminedLater.size; | 760 // ui::kWindowSizeDeterminedLater. |
729 [window_ setFrame:frame display:YES]; | 761 DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.width, |
762 [window_ frame].size.width); | |
763 DCHECK_EQ(ui::kWindowSizeDeterminedLater.size.height, | |
764 [window_ frame].size.height); | |
730 return; | 765 return; |
731 } | 766 } |
732 | 767 |
733 SetFrameAvoidingMouse(CalculateWindowFrame(/*expand=*/false), | 768 SetFrameAvoidingMouse(CalculateWindowFrame(/*expand=*/false), |
734 GetMouseLocation()); | 769 GetMouseLocation()); |
735 } | 770 } |
736 | 771 |
737 void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) { | 772 void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) { |
738 DCHECK(parent); | 773 DCHECK(parent); |
739 DCHECK(is_attached()); | 774 DCHECK(is_attached()); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
788 } | 823 } |
789 | 824 |
790 // Round the top corners when the bubble is below the parent window. | 825 // Round the top corners when the bubble is below the parent window. |
791 if (NSMinY(window_frame) < NSMinY(parent_frame)) { | 826 if (NSMinY(window_frame) < NSMinY(parent_frame)) { |
792 corner_flags |= kRoundedTopLeftCorner | kRoundedTopRightCorner; | 827 corner_flags |= kRoundedTopLeftCorner | kRoundedTopRightCorner; |
793 } | 828 } |
794 } | 829 } |
795 | 830 |
796 return corner_flags; | 831 return corner_flags; |
797 } | 832 } |
OLD | NEW |