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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/profiles/avatar_menu.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
11 #include "chrome/browser/profiles/profile_info_cache.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "chrome/browser/profiles/profiles_state.h"
14 #include "chrome/browser/themes/theme_properties.h"
15 #include "chrome/browser/ui/view_ids.h"
16 #include "chrome/browser/ui/views/frame/browser_view.h"
17 #include "chrome/browser/ui/views/frame/taskbar_decorator.h"
18 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
19 #include "chrome/browser/ui/views/profiles/new_avatar_button.h"
20 #include "chrome/browser/ui/views/tabs/tab_strip.h"
21 #include "chrome/browser/ui/views/theme_image_mapper.h"
22 #include "components/signin/core/common/profile_management_switches.h"
23 #include "grit/theme_resources.h"
24 #include "third_party/skia/include/core/SkColor.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/base/theme_provider.h"
27 #include "ui/gfx/image/image.h"
28 #include "ui/resources/grit/ui_resources.h"
29 #include "ui/views/background.h"
30 #include "ui/views/resources/grit/views_resources.h"
32 #if defined(ENABLE_SUPERVISED_USERS)
33 #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h"
36 BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame
* frame
,
37 BrowserView
* browser_view
)
39 browser_view_(browser_view
),
40 #if defined(ENABLE_SUPERVISED_USERS)
41 supervised_user_avatar_label_(nullptr),
43 #if defined(FRAME_AVATAR_BUTTON)
44 new_avatar_button_(nullptr),
46 avatar_button_(nullptr) {
47 // The profile manager may by null in tests.
48 if (g_browser_process
->profile_manager()) {
49 ProfileInfoCache
& cache
=
50 g_browser_process
->profile_manager()->GetProfileInfoCache();
51 cache
.AddObserver(this);
55 BrowserNonClientFrameView::~BrowserNonClientFrameView() {
56 // The profile manager may by null in tests.
57 if (g_browser_process
->profile_manager()) {
58 ProfileInfoCache
& cache
=
59 g_browser_process
->profile_manager()->GetProfileInfoCache();
60 cache
.RemoveObserver(this);
64 void BrowserNonClientFrameView::UpdateToolbar() {
67 views::View
* BrowserNonClientFrameView::GetLocationIconView() const {
71 void BrowserNonClientFrameView::VisibilityChanged(views::View
* starting_from
,
76 // The first time UpdateOldAvatarButton() is called the window is not visible
77 // so DrawTaskBarDecoration() has no effect. Therefore we need to call it
78 // again once the window is visible.
79 if (!browser_view_
->IsRegularOrGuestSession() ||
80 !switches::IsNewAvatarMenu()) {
81 UpdateOldAvatarButton();
84 // Make sure the task bar icon is correctly updated call
85 // |OnProfileAvatarChanged()| in this case, but only for non guest profiles.
86 if (!browser_view_
->IsGuestSession() || !switches::IsNewAvatarMenu())
87 OnProfileAvatarChanged(base::FilePath());
90 void BrowserNonClientFrameView::ChildPreferredSizeChanged(View
* child
) {
91 #if defined(FRAME_AVATAR_BUTTON)
92 // Only perform a re-layout if the avatar button has changed, since that
93 // can affect the size of the tabs.
94 if (child
== new_avatar_button_
) {
96 frame_
->GetRootView()->Layout();
101 #if defined(ENABLE_SUPERVISED_USERS)
102 void BrowserNonClientFrameView::OnThemeChanged() {
103 if (supervised_user_avatar_label_
)
104 supervised_user_avatar_label_
->UpdateLabelStyle();
108 bool BrowserNonClientFrameView::ShouldPaintAsThemed() const {
109 return browser_view_
->IsBrowserTypeNormal();
112 SkColor
BrowserNonClientFrameView::GetFrameColor() const {
113 const bool incognito
= browser_view_
->IsOffTheRecord();
114 ThemeProperties::OverwritableByUserThemeProperty color_id
;
115 if (ShouldPaintAsActive()) {
116 color_id
= incognito
? ThemeProperties::COLOR_FRAME_INCOGNITO
117 : ThemeProperties::COLOR_FRAME
;
119 color_id
= incognito
? ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE
120 : ThemeProperties::COLOR_FRAME_INACTIVE
;
122 return ShouldPaintAsThemed() ? GetThemeProvider()->GetColor(color_id
)
123 : ThemeProperties::GetDefaultColor(color_id
);
126 gfx::ImageSkia
* BrowserNonClientFrameView::GetFrameImage() const {
127 const bool incognito
= browser_view_
->IsOffTheRecord();
129 if (browser_view_
->IsBrowserTypeNormal()) {
130 if (ShouldPaintAsActive()) {
131 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO
: IDR_THEME_FRAME
;
133 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO_INACTIVE
134 : IDR_THEME_FRAME_INACTIVE
;
136 return GetThemeProvider()->GetImageSkiaNamed(resource_id
);
139 if (ShouldPaintAsActive()) {
140 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO
: IDR_FRAME
;
142 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO_INACTIVE
143 : IDR_THEME_FRAME_INACTIVE
;
146 if (ShouldPaintAsThemed()) {
147 // On Linux, we want to use theme images provided by the system theme when
148 // enabled, even if we are an app or popup window.
149 return GetThemeProvider()->GetImageSkiaNamed(resource_id
);
152 // Otherwise, never theme app and popup windows.
153 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
154 return rb
.GetImageSkiaNamed(
155 chrome::MapThemeImage(chrome::GetHostDesktopTypeForNativeWindow(
156 browser_view_
->GetNativeWindow()),
160 gfx::ImageSkia
* BrowserNonClientFrameView::GetFrameOverlayImage() const {
161 ui::ThemeProvider
* tp
= GetThemeProvider();
162 if (tp
->HasCustomImage(IDR_THEME_FRAME_OVERLAY
) &&
163 browser_view_
->IsBrowserTypeNormal() &&
164 !browser_view_
->IsOffTheRecord()) {
165 return tp
->GetImageSkiaNamed(ShouldPaintAsActive() ?
166 IDR_THEME_FRAME_OVERLAY
: IDR_THEME_FRAME_OVERLAY_INACTIVE
);
171 int BrowserNonClientFrameView::GetTopAreaHeight() const {
172 gfx::ImageSkia
* frame_image
= GetFrameImage();
173 int top_area_height
= frame_image
->height();
174 if (browser_view_
->IsTabStripVisible()) {
175 top_area_height
= std::max(top_area_height
,
176 GetBoundsForTabStrip(browser_view_
->tabstrip()).bottom());
178 return top_area_height
;
181 void BrowserNonClientFrameView::UpdateAvatar() {
182 if (browser_view()->IsRegularOrGuestSession() && switches::IsNewAvatarMenu())
183 UpdateNewAvatarButtonImpl();
185 UpdateOldAvatarButton();
188 void BrowserNonClientFrameView::UpdateOldAvatarButton() {
189 if (browser_view_
->ShouldShowAvatar()) {
190 if (!avatar_button_
) {
191 #if defined(ENABLE_SUPERVISED_USERS)
192 Profile
* profile
= browser_view_
->browser()->profile();
193 if (profile
->IsSupervised() && !supervised_user_avatar_label_
) {
194 supervised_user_avatar_label_
=
195 new SupervisedUserAvatarLabel(browser_view_
);
196 supervised_user_avatar_label_
->set_id(
197 VIEW_ID_SUPERVISED_USER_AVATAR_LABEL
);
198 AddChildView(supervised_user_avatar_label_
);
201 avatar_button_
= new AvatarMenuButton(
202 browser_view_
->browser(), !browser_view_
->IsRegularOrGuestSession());
203 avatar_button_
->set_id(VIEW_ID_AVATAR_BUTTON
);
204 AddChildView(avatar_button_
);
205 // Invalidate here because adding a child does not invalidate the layout.
207 frame_
->GetRootView()->Layout();
209 } else if (avatar_button_
) {
210 #if defined(ENABLE_SUPERVISED_USERS)
211 // The avatar label can just be there if there is also an avatar button.
212 if (supervised_user_avatar_label_
) {
213 RemoveChildView(supervised_user_avatar_label_
);
214 delete supervised_user_avatar_label_
;
215 supervised_user_avatar_label_
= nullptr;
218 RemoveChildView(avatar_button_
);
219 delete avatar_button_
;
220 avatar_button_
= nullptr;
221 frame_
->GetRootView()->Layout();
225 gfx::Image taskbar_badge_avatar
;
226 bool is_rectangle
= false;
228 // Update the avatar button in the window frame and the taskbar overlay.
229 bool should_show_avatar_menu
=
230 avatar_button_
|| AvatarMenu::ShouldShowAvatarMenu();
232 if (!AvatarMenuButton::GetAvatarImages(
233 browser_view_
->browser()->profile(), should_show_avatar_menu
, &avatar
,
234 &taskbar_badge_avatar
, &is_rectangle
)) {
238 // Disable the menu when we should not show the menu.
239 if (avatar_button_
&& !AvatarMenu::ShouldShowAvatarMenu())
240 avatar_button_
->SetEnabled(false);
242 avatar_button_
->SetAvatarIcon(avatar
, is_rectangle
);
245 #if defined(FRAME_AVATAR_BUTTON)
246 void BrowserNonClientFrameView::UpdateNewAvatarButton(
247 views::ButtonListener
* listener
,
248 const NewAvatarButton::AvatarButtonStyle style
) {
249 DCHECK(switches::IsNewAvatarMenu());
250 // This should never be called in incognito mode.
251 DCHECK(browser_view_
->IsRegularOrGuestSession());
253 if (browser_view_
->ShouldShowAvatar()) {
254 if (!new_avatar_button_
) {
256 new NewAvatarButton(listener
, style
, browser_view_
->browser());
257 new_avatar_button_
->set_id(VIEW_ID_NEW_AVATAR_BUTTON
);
258 AddChildView(new_avatar_button_
);
259 frame_
->GetRootView()->Layout();
261 } else if (new_avatar_button_
) {
262 delete new_avatar_button_
;
263 new_avatar_button_
= nullptr;
264 frame_
->GetRootView()->Layout();
269 void BrowserNonClientFrameView::OnProfileAdded(
270 const base::FilePath
& profile_path
) {
271 UpdateTaskbarDecoration();
275 void BrowserNonClientFrameView::OnProfileWasRemoved(
276 const base::FilePath
& profile_path
,
277 const base::string16
& profile_name
) {
278 UpdateTaskbarDecoration();
282 void BrowserNonClientFrameView::OnProfileAvatarChanged(
283 const base::FilePath
& profile_path
) {
284 UpdateTaskbarDecoration();
285 // Profile avatars are only displayed in the old UI or incognito.
286 if ((!browser_view()->IsGuestSession() && browser_view()->IsOffTheRecord()) ||
287 !switches::IsNewAvatarMenu()) {
288 UpdateOldAvatarButton();
292 void BrowserNonClientFrameView::UpdateTaskbarDecoration() {
294 gfx::Image taskbar_badge_avatar
;
296 // Only need to update the taskbar overlay here. If GetAvatarImages()
297 // returns false, don't bother trying to update the taskbar decoration since
298 // the returned images are not initialized. This can happen if the user
299 // deletes the current profile.
300 if (AvatarMenuButton::GetAvatarImages(browser_view_
->browser()->profile(),
301 AvatarMenu::ShouldShowAvatarMenu(),
302 &avatar
, &taskbar_badge_avatar
,
304 // For popups and panels which don't have the avatar button, we still
305 // need to draw the taskbar decoration. Even though we have an icon on the
306 // window's relaunch details, we draw over it because the user may have
307 // pinned the badge-less Chrome shortcut which will cause windows to ignore
308 // the relaunch details.
309 // TODO(calamity): ideally this should not be necessary but due to issues
310 // with the default shortcut being pinned, we add the runtime badge for
311 // safety. See crbug.com/313800.
312 bool show_decoration
= AvatarMenu::ShouldShowAvatarMenu() &&
313 !browser_view_
->browser()->profile()->IsGuestSession();
314 // In tests, make sure that the browser process and profile manager are
315 // valid before using.
316 if (g_browser_process
&& g_browser_process
->profile_manager()) {
317 const ProfileInfoCache
& cache
=
318 g_browser_process
->profile_manager()->GetProfileInfoCache();
319 show_decoration
= show_decoration
&& cache
.GetNumberOfProfiles() > 1;
321 chrome::DrawTaskbarDecoration(frame_
->GetNativeWindow(),
323 ? (taskbar_badge_avatar
.IsEmpty() ? &avatar
: &taskbar_badge_avatar
)