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/views/frame/glass_browser_frame_view.h" | 5 #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h" |
6 | 6 |
7 #include <dwmapi.h> | 7 #include <dwmapi.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/win/windows_version.h" | 10 #include "base/win/windows_version.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 namespace { | 42 namespace { |
43 // Thickness of the frame edge between the non-client area and the web content. | 43 // Thickness of the frame edge between the non-client area and the web content. |
44 const int kClientBorderThickness = 3; | 44 const int kClientBorderThickness = 3; |
45 // Besides the frame border, there's empty space atop the window in restored | 45 // Besides the frame border, there's empty space atop the window in restored |
46 // mode, to use to drag the window around. | 46 // mode, to use to drag the window around. |
47 const int kNonClientRestoredExtraThickness = 11; | 47 const int kNonClientRestoredExtraThickness = 11; |
48 // At the window corners the resize area is not actually bigger, but the 16 | 48 // At the window corners the resize area is not actually bigger, but the 16 |
49 // pixels at the end of the top and bottom edges trigger diagonal resizing. | 49 // pixels at the end of the top and bottom edges trigger diagonal resizing. |
50 const int kResizeCornerWidth = 16; | 50 const int kResizeCornerWidth = 16; |
51 // How far the profile switcher button is from the left of the minimize button. | 51 // How far the profile switcher button is from the left of the minimize button. |
52 const int kProfileSwitcherButtonOffset = 5; | 52 const int kProfileSwitcherButtonOffset = 1; |
53 // The content edge images have a shadow built into them. | 53 // The content edge images have a shadow built into them. |
54 const int kContentEdgeShadowThickness = 2; | 54 const int kContentEdgeShadowThickness = 2; |
55 // In restored mode, the New Tab button isn't at the same height as the caption | 55 // In restored mode, the New Tab button isn't at the same height as the caption |
56 // buttons, but the space will look cluttered if it actually slides under them, | 56 // buttons, but the space will look cluttered if it actually slides under them, |
57 // so we stop it when the gap between the two is down to 5 px. | 57 // so we stop it when the gap between the two is down to 5 px. |
58 const int kNewTabCaptionRestoredSpacing = 5; | 58 const int kNewTabCaptionRestoredSpacing = 5; |
59 // In maximized mode, where the New Tab button and the caption buttons are at | 59 // In maximized mode, where the New Tab button and the caption buttons are at |
60 // similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid | 60 // similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid |
61 // looking too cluttered. | 61 // looking too cluttered. |
62 const int kNewTabCaptionMaximizedSpacing = 16; | 62 const int kNewTabCaptionMaximizedSpacing = 16; |
63 // Height of the profile switcher button. Same as the height of the Windows 7/8 | |
64 // caption buttons. | |
65 // TODO(bsep): Windows 10 caption buttons look very different and we would like | |
66 // the profile switcher button to match on that platform. | |
67 const int kProfileSwitcherButtonHeight = 20; | |
68 // There is a small one-pixel strip right above the caption buttons in which the | 63 // There is a small one-pixel strip right above the caption buttons in which the |
69 // resize border "peeks" through. | 64 // resize border "peeks" through. |
70 const int kCaptionButtonTopInset = 1; | 65 const int kCaptionButtonTopInset = 1; |
71 | 66 |
72 // Converts the |image| to a Windows icon and returns the corresponding HICON | 67 // Converts the |image| to a Windows icon and returns the corresponding HICON |
73 // handle. |image| is resized to desired |width| and |height| if needed. | 68 // handle. |image| is resized to desired |width| and |height| if needed. |
74 base::win::ScopedHICON CreateHICONFromSkBitmapSizedTo( | 69 base::win::ScopedHICON CreateHICONFromSkBitmapSizedTo( |
75 const gfx::ImageSkia& image, | 70 const gfx::ImageSkia& image, |
76 int width, | 71 int width, |
77 int height) { | 72 int height) { |
(...skipping 14 matching lines...) Expand all Loading... |
92 BrowserView* browser_view) | 87 BrowserView* browser_view) |
93 : BrowserNonClientFrameView(frame, browser_view), | 88 : BrowserNonClientFrameView(frame, browser_view), |
94 window_icon_(nullptr), | 89 window_icon_(nullptr), |
95 window_title_(nullptr), | 90 window_title_(nullptr), |
96 profile_switcher_(this), | 91 profile_switcher_(this), |
97 minimize_button_(nullptr), | 92 minimize_button_(nullptr), |
98 maximize_button_(nullptr), | 93 maximize_button_(nullptr), |
99 restore_button_(nullptr), | 94 restore_button_(nullptr), |
100 close_button_(nullptr), | 95 close_button_(nullptr), |
101 throbber_running_(false), | 96 throbber_running_(false), |
102 throbber_frame_(0) { | 97 throbber_frame_(0), |
| 98 tab_strip_observer_(this) { |
103 // We initialize all fields despite some of them being unused in some modes, | 99 // We initialize all fields despite some of them being unused in some modes, |
104 // since it's possible for modes to flip dynamically (e.g. if the user enables | 100 // since it's possible for modes to flip dynamically (e.g. if the user enables |
105 // a high-contrast theme). Throbber icons are only used when ShowSystemIcon() | 101 // a high-contrast theme). Throbber icons are only used when ShowSystemIcon() |
106 // is true. Everything else here is only used when | 102 // is true. Everything else here is only used when |
107 // ShouldCustomDrawSystemTitlebar() is true. | 103 // ShouldCustomDrawSystemTitlebar() is true. |
108 | 104 |
109 if (browser_view->ShouldShowWindowIcon()) { | 105 if (browser_view->ShouldShowWindowIcon()) { |
110 InitThrobberIcons(); | 106 InitThrobberIcons(); |
111 | 107 |
112 window_icon_ = new TabIconView(this, nullptr); | 108 window_icon_ = new TabIconView(this, nullptr); |
(...skipping 28 matching lines...) Expand all Loading... |
141 views::View* tabstrip) const { | 137 views::View* tabstrip) const { |
142 const int x = incognito_bounds_.right() + kAvatarIconPadding; | 138 const int x = incognito_bounds_.right() + kAvatarIconPadding; |
143 int end_x = width() - ClientBorderThickness(false); | 139 int end_x = width() - ClientBorderThickness(false); |
144 if (!CaptionButtonsOnLeadingEdge()) { | 140 if (!CaptionButtonsOnLeadingEdge()) { |
145 end_x = std::min(MinimizeButtonX(), end_x) - | 141 end_x = std::min(MinimizeButtonX(), end_x) - |
146 (IsMaximized() ? kNewTabCaptionMaximizedSpacing | 142 (IsMaximized() ? kNewTabCaptionMaximizedSpacing |
147 : kNewTabCaptionRestoredSpacing); | 143 : kNewTabCaptionRestoredSpacing); |
148 | 144 |
149 // The profile switcher button is optionally displayed to the left of the | 145 // The profile switcher button is optionally displayed to the left of the |
150 // minimize button. | 146 // minimize button. |
151 if (profile_switcher_.view()) { | 147 views::View* profile_switcher = GetProfileSwitcherView(); |
| 148 if (profile_switcher) { |
152 const int old_end_x = end_x; | 149 const int old_end_x = end_x; |
153 end_x -= profile_switcher_.view()->width() + kProfileSwitcherButtonOffset; | 150 end_x -= profile_switcher->width() + kProfileSwitcherButtonOffset; |
154 | 151 |
155 // In non-maximized mode, allow the new tab button to slide completely | 152 // In non-maximized mode, allow the new tab button to slide completely |
156 // under the profile switcher button. | 153 // under the profile switcher button. |
157 if (!IsMaximized()) { | 154 if (!IsMaximized()) { |
158 end_x = std::min(end_x + GetLayoutSize(NEW_TAB_BUTTON).width() + | 155 end_x = std::min(end_x + GetLayoutSize(NEW_TAB_BUTTON).width() + |
159 kNewTabCaptionRestoredSpacing, | 156 kNewTabCaptionRestoredSpacing, |
160 old_end_x); | 157 old_end_x); |
161 } | 158 } |
162 } | 159 } |
163 } | 160 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 min_size.set_width(std::max(min_tabstrip_area_width, min_size.width())); | 207 min_size.set_width(std::max(min_tabstrip_area_width, min_size.width())); |
211 } | 208 } |
212 | 209 |
213 return min_size; | 210 return min_size; |
214 } | 211 } |
215 | 212 |
216 views::View* GlassBrowserFrameView::GetProfileSwitcherView() const { | 213 views::View* GlassBrowserFrameView::GetProfileSwitcherView() const { |
217 return profile_switcher_.view(); | 214 return profile_switcher_.view(); |
218 } | 215 } |
219 | 216 |
| 217 void GlassBrowserFrameView::OnBrowserViewInitViewsComplete() { |
| 218 if (browser_view()->tabstrip()) { |
| 219 DCHECK(!tab_strip_observer_.IsObserving(browser_view()->tabstrip())); |
| 220 tab_strip_observer_.Add(browser_view()->tabstrip()); |
| 221 } |
| 222 } |
| 223 |
220 /////////////////////////////////////////////////////////////////////////////// | 224 /////////////////////////////////////////////////////////////////////////////// |
221 // GlassBrowserFrameView, views::NonClientFrameView implementation: | 225 // GlassBrowserFrameView, views::NonClientFrameView implementation: |
222 | 226 |
223 gfx::Rect GlassBrowserFrameView::GetBoundsForClientView() const { | 227 gfx::Rect GlassBrowserFrameView::GetBoundsForClientView() const { |
224 return client_view_bounds_; | 228 return client_view_bounds_; |
225 } | 229 } |
226 | 230 |
227 gfx::Rect GlassBrowserFrameView::GetWindowBoundsForClientBounds( | 231 gfx::Rect GlassBrowserFrameView::GetWindowBoundsForClientBounds( |
228 const gfx::Rect& client_bounds) const { | 232 const gfx::Rect& client_bounds) const { |
229 HWND hwnd = views::HWNDForWidget(frame()); | 233 HWND hwnd = views::HWNDForWidget(frame()); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 const content::WebContents* current_tab = | 372 const content::WebContents* current_tab = |
369 browser_view()->GetActiveWebContents(); | 373 browser_view()->GetActiveWebContents(); |
370 return current_tab && current_tab->IsLoading(); | 374 return current_tab && current_tab->IsLoading(); |
371 } | 375 } |
372 | 376 |
373 gfx::ImageSkia GlassBrowserFrameView::GetFaviconForTabIconView() { | 377 gfx::ImageSkia GlassBrowserFrameView::GetFaviconForTabIconView() { |
374 DCHECK(ShowCustomIcon()); | 378 DCHECK(ShowCustomIcon()); |
375 return frame()->widget_delegate()->GetWindowIcon(); | 379 return frame()->widget_delegate()->GetWindowIcon(); |
376 } | 380 } |
377 | 381 |
| 382 void GlassBrowserFrameView::TabStripMaxXChanged(TabStrip* tab_strip) { |
| 383 // The profile switcher button's height depends on the position of the new |
| 384 // tab button. |
| 385 if (browser_view()->IsRegularOrGuestSession()) |
| 386 LayoutProfileSwitcher(); |
| 387 } |
| 388 |
| 389 void GlassBrowserFrameView::TabStripRemovedTabAt(TabStrip* tab_strip, |
| 390 int index) { |
| 391 // The profile switcher button may need to change height here, too. |
| 392 // TabStripMaxXChanged is not enough when a tab other than the last tab is |
| 393 // closed. |
| 394 if (browser_view()->IsRegularOrGuestSession()) |
| 395 LayoutProfileSwitcher(); |
| 396 } |
| 397 |
| 398 void GlassBrowserFrameView::TabStripDeleted(TabStrip* tab_strip) { |
| 399 // The tab strip is currently never deleted before the frame. If that changes |
| 400 // tab_strip_observer_.Remove(tab_strip) may be needed here. |
| 401 NOTREACHED(); |
| 402 } |
| 403 |
378 bool GlassBrowserFrameView::IsMaximized() const { | 404 bool GlassBrowserFrameView::IsMaximized() const { |
379 return frame()->IsMaximized(); | 405 return frame()->IsMaximized(); |
380 } | 406 } |
381 | 407 |
382 /////////////////////////////////////////////////////////////////////////////// | 408 /////////////////////////////////////////////////////////////////////////////// |
383 // GlassBrowserFrameView, views::View overrides: | 409 // GlassBrowserFrameView, views::View overrides: |
384 | 410 |
385 void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) { | 411 void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) { |
386 if (ShouldCustomDrawSystemTitlebar()) | 412 if (ShouldCustomDrawSystemTitlebar()) |
387 PaintTitlebar(canvas); | 413 PaintTitlebar(canvas); |
(...skipping 11 matching lines...) Expand all Loading... |
399 // must be called prior to LayoutProfileSwitcher(). | 425 // must be called prior to LayoutProfileSwitcher(). |
400 LayoutCaptionButtons(); | 426 LayoutCaptionButtons(); |
401 LayoutTitleBar(); | 427 LayoutTitleBar(); |
402 } | 428 } |
403 if (browser_view()->IsRegularOrGuestSession()) | 429 if (browser_view()->IsRegularOrGuestSession()) |
404 LayoutProfileSwitcher(); | 430 LayoutProfileSwitcher(); |
405 LayoutIncognitoIcon(); | 431 LayoutIncognitoIcon(); |
406 LayoutClientView(); | 432 LayoutClientView(); |
407 } | 433 } |
408 | 434 |
| 435 void GlassBrowserFrameView::ChildPreferredSizeChanged(views::View* child) { |
| 436 if (child == GetProfileSwitcherView()) { |
| 437 // Need to layout the root view here, too, as the avatar button may change |
| 438 // between the text and the icon when a profile is added or removed, which |
| 439 // changes its width. This may cause it to start or stop overlapping the |
| 440 // the tabstrip horizontally, which in turn causes it to change height, as |
| 441 // calculated in LayoutProfileSwitcher(). Calling LayoutProfileSwitcher() |
| 442 // is not enough here - it does not re-draw the line below the tabstrip |
| 443 // properly when a profile is added or removed. Even adding |
| 444 // browser_view()->tabstrip()->Layout() and SchedulePaint() is not enough. |
| 445 // TODO(bsep): Figure out the most efficient way to do this. |
| 446 frame()->GetRootView()->Layout(); |
| 447 } |
| 448 } |
| 449 |
409 /////////////////////////////////////////////////////////////////////////////// | 450 /////////////////////////////////////////////////////////////////////////////// |
410 // GlassBrowserFrameView, protected: | 451 // GlassBrowserFrameView, protected: |
411 | 452 |
412 // BrowserNonClientFrameView: | 453 // BrowserNonClientFrameView: |
413 void GlassBrowserFrameView::UpdateProfileIcons() { | 454 void GlassBrowserFrameView::UpdateProfileIcons() { |
414 if (browser_view()->IsRegularOrGuestSession()) | 455 if (browser_view()->IsRegularOrGuestSession()) |
415 profile_switcher_.Update(AvatarButtonStyle::NATIVE); | 456 profile_switcher_.Update(AvatarButtonStyle::NATIVE); |
416 else | 457 else |
417 UpdateProfileIndicatorIcon(); | 458 UpdateProfileIndicatorIcon(); |
418 } | 459 } |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 bottom + kClientEdgeThickness - y); | 751 bottom + kClientEdgeThickness - y); |
711 canvas->FillRect(side, color); | 752 canvas->FillRect(side, color); |
712 canvas->FillRect(gfx::Rect(x, bottom, right - x, kClientEdgeThickness), | 753 canvas->FillRect(gfx::Rect(x, bottom, right - x, kClientEdgeThickness), |
713 color); | 754 color); |
714 side.set_x(right); | 755 side.set_x(right); |
715 canvas->FillRect(side, color); | 756 canvas->FillRect(side, color); |
716 } | 757 } |
717 | 758 |
718 void GlassBrowserFrameView::LayoutProfileSwitcher() { | 759 void GlassBrowserFrameView::LayoutProfileSwitcher() { |
719 DCHECK(browser_view()->IsRegularOrGuestSession()); | 760 DCHECK(browser_view()->IsRegularOrGuestSession()); |
720 if (!profile_switcher_.view()) | 761 |
| 762 View* profile_switcher = profile_switcher_.view(); |
| 763 if (!profile_switcher) |
721 return; | 764 return; |
722 | 765 |
723 gfx::Size label_size = profile_switcher_.view()->GetPreferredSize(); | 766 gfx::Size button_size = profile_switcher->GetPreferredSize(); |
| 767 int button_width = button_size.width(); |
| 768 int button_height = button_size.height(); |
724 | 769 |
725 int button_x; | 770 int button_x; |
726 if (CaptionButtonsOnLeadingEdge()) { | 771 if (CaptionButtonsOnLeadingEdge()) { |
727 button_x = width() - frame()->GetMinimizeButtonOffset() + | 772 button_x = width() - frame()->GetMinimizeButtonOffset() + |
728 kProfileSwitcherButtonOffset; | 773 kProfileSwitcherButtonOffset; |
729 } else { | 774 } else { |
730 button_x = | 775 button_x = MinimizeButtonX() - kProfileSwitcherButtonOffset - button_width; |
731 MinimizeButtonX() - kProfileSwitcherButtonOffset - label_size.width(); | |
732 } | 776 } |
733 | 777 |
734 int button_y = WindowTopY(); | 778 int button_y = WindowTopY(); |
735 if (IsMaximized()) { | 779 if (IsMaximized()) { |
736 // In maximized mode the caption buttons appear only 19 pixels high, but | 780 // In maximized mode the caption buttons appear only 19 pixels high, but |
737 // their contents are aligned as if they were 20 pixels high and extended | 781 // their contents are aligned as if they were 20 pixels high and extended |
738 // 1 pixel off the top of the screen. We position the profile switcher | 782 // 1 pixel off the top of the screen. We position the profile switcher |
739 // button the same way to match. | 783 // button the same way to match. |
740 button_y -= 1; | 784 button_y -= 1; |
741 } | 785 } |
742 profile_switcher_.view()->SetBounds(button_x, button_y, label_size.width(), | 786 |
743 kProfileSwitcherButtonHeight); | 787 // Shrink the button height when it's atop part of the tabstrip. In RTL the |
| 788 // new tab button is on the left, so it can never slide under the avatar |
| 789 // button, which is still on the right [http://crbug.com/560619]. |
| 790 TabStrip* tabstrip = browser_view()->tabstrip(); |
| 791 if (tabstrip && !base::i18n::IsRTL() && tabstrip->max_x() >= button_x) |
| 792 button_height = profile_switcher->GetMinimumSize().height(); |
| 793 |
| 794 profile_switcher->SetBounds(button_x, button_y, button_width, button_height); |
744 } | 795 } |
745 | 796 |
746 void GlassBrowserFrameView::LayoutIncognitoIcon() { | 797 void GlassBrowserFrameView::LayoutIncognitoIcon() { |
747 const gfx::Size size(GetIncognitoAvatarIcon().size()); | 798 const gfx::Size size(GetIncognitoAvatarIcon().size()); |
748 int x = ClientBorderThickness(false); | 799 int x = ClientBorderThickness(false); |
749 // In RTL, the icon needs to start after the caption buttons. | 800 // In RTL, the icon needs to start after the caption buttons. |
750 if (CaptionButtonsOnLeadingEdge()) { | 801 if (CaptionButtonsOnLeadingEdge()) { |
751 x = width() - frame()->GetMinimizeButtonOffset() + | 802 x = width() - frame()->GetMinimizeButtonOffset() + |
752 (profile_switcher_.view() ? (profile_switcher_.view()->width() + | 803 (GetProfileSwitcherView() ? (GetProfileSwitcherView()->width() + |
753 kProfileSwitcherButtonOffset) | 804 kProfileSwitcherButtonOffset) |
754 : 0); | 805 : 0); |
755 } | 806 } |
756 const int bottom = GetTopInset(false) + browser_view()->GetTabStripHeight() - | 807 const int bottom = GetTopInset(false) + browser_view()->GetTabStripHeight() - |
757 kAvatarIconPadding; | 808 kAvatarIconPadding; |
758 incognito_bounds_.SetRect( | 809 incognito_bounds_.SetRect( |
759 x + (profile_indicator_icon() ? kAvatarIconPadding : 0), | 810 x + (profile_indicator_icon() ? kAvatarIconPadding : 0), |
760 bottom - size.height(), profile_indicator_icon() ? size.width() : 0, | 811 bottom - size.height(), profile_indicator_icon() ? size.width() : 0, |
761 size.height()); | 812 size.height()); |
762 if (profile_indicator_icon()) | 813 if (profile_indicator_icon()) |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
915 static bool initialized = false; | 966 static bool initialized = false; |
916 if (!initialized) { | 967 if (!initialized) { |
917 for (int i = 0; i < kThrobberIconCount; ++i) { | 968 for (int i = 0; i < kThrobberIconCount; ++i) { |
918 throbber_icons_[i] = | 969 throbber_icons_[i] = |
919 ui::LoadThemeIconFromResourcesDataDLL(IDI_THROBBER_01 + i); | 970 ui::LoadThemeIconFromResourcesDataDLL(IDI_THROBBER_01 + i); |
920 DCHECK(throbber_icons_[i]); | 971 DCHECK(throbber_icons_[i]); |
921 } | 972 } |
922 initialized = true; | 973 initialized = true; |
923 } | 974 } |
924 } | 975 } |
OLD | NEW |