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"
31 #if defined(ENABLE_SUPERVISED_USERS)
32 #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h"
35 BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame
* frame
,
36 BrowserView
* browser_view
)
38 browser_view_(browser_view
),
39 avatar_button_(nullptr),
40 #if defined(ENABLE_SUPERVISED_USERS)
41 supervised_user_avatar_label_(nullptr),
43 new_avatar_button_(nullptr) {
44 // The profile manager may by null in tests.
45 if (g_browser_process
->profile_manager()) {
46 ProfileInfoCache
& cache
=
47 g_browser_process
->profile_manager()->GetProfileInfoCache();
48 cache
.AddObserver(this);
52 BrowserNonClientFrameView::~BrowserNonClientFrameView() {
53 // The profile manager may by null in tests.
54 if (g_browser_process
->profile_manager()) {
55 ProfileInfoCache
& cache
=
56 g_browser_process
->profile_manager()->GetProfileInfoCache();
57 cache
.RemoveObserver(this);
61 void BrowserNonClientFrameView::UpdateToolbar() {
64 views::View
* BrowserNonClientFrameView::GetLocationIconView() const {
68 void BrowserNonClientFrameView::VisibilityChanged(views::View
* starting_from
,
73 // The first time UpdateOldAvatarButton() is called the window is not visible
74 // so DrawTaskBarDecoration() has no effect. Therefore we need to call it
75 // again once the window is visible.
76 if (!browser_view_
->IsRegularOrGuestSession() ||
77 !switches::IsNewAvatarMenu()) {
78 UpdateOldAvatarButton();
81 // Make sure the task bar icon is correctly updated call
82 // |OnProfileAvatarChanged()| in this case, but only for non guest profiles.
83 if (!browser_view_
->IsGuestSession() || !switches::IsNewAvatarMenu())
84 OnProfileAvatarChanged(base::FilePath());
87 void BrowserNonClientFrameView::ChildPreferredSizeChanged(View
* child
) {
88 // Only perform a re-layout if the avatar button has changed, since that
89 // can affect the size of the tabs.
90 if (child
== new_avatar_button_
) {
92 frame_
->GetRootView()->Layout();
96 #if defined(ENABLE_SUPERVISED_USERS)
97 void BrowserNonClientFrameView::OnThemeChanged() {
98 if (supervised_user_avatar_label_
)
99 supervised_user_avatar_label_
->UpdateLabelStyle();
103 bool BrowserNonClientFrameView::ShouldPaintAsThemed() const {
104 return browser_view_
->IsBrowserTypeNormal();
107 SkColor
BrowserNonClientFrameView::GetFrameColor() const {
108 const bool incognito
= browser_view_
->IsOffTheRecord();
109 ThemeProperties::OverwritableByUserThemeProperty color_id
;
110 if (ShouldPaintAsActive()) {
111 color_id
= incognito
? ThemeProperties::COLOR_FRAME_INCOGNITO
112 : ThemeProperties::COLOR_FRAME
;
114 color_id
= incognito
? ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE
115 : ThemeProperties::COLOR_FRAME_INACTIVE
;
117 return ShouldPaintAsThemed() ? GetThemeProvider()->GetColor(color_id
)
118 : ThemeProperties::GetDefaultColor(color_id
);
121 gfx::ImageSkia
* BrowserNonClientFrameView::GetFrameImage() const {
122 const bool incognito
= browser_view_
->IsOffTheRecord();
124 if (browser_view_
->IsBrowserTypeNormal()) {
125 if (ShouldPaintAsActive()) {
126 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO
: IDR_THEME_FRAME
;
128 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO_INACTIVE
129 : IDR_THEME_FRAME_INACTIVE
;
131 return GetThemeProvider()->GetImageSkiaNamed(resource_id
);
134 if (ShouldPaintAsActive()) {
135 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO
: IDR_FRAME
;
137 resource_id
= incognito
? IDR_THEME_FRAME_INCOGNITO_INACTIVE
138 : IDR_THEME_FRAME_INACTIVE
;
141 if (ShouldPaintAsThemed()) {
142 // On Linux, we want to use theme images provided by the system theme when
143 // enabled, even if we are an app or popup window.
144 return GetThemeProvider()->GetImageSkiaNamed(resource_id
);
147 // Otherwise, never theme app and popup windows.
148 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
149 return rb
.GetImageSkiaNamed(
150 chrome::MapThemeImage(chrome::GetHostDesktopTypeForNativeWindow(
151 browser_view_
->GetNativeWindow()),
155 gfx::ImageSkia
* BrowserNonClientFrameView::GetFrameOverlayImage() const {
156 ui::ThemeProvider
* tp
= GetThemeProvider();
157 if (tp
->HasCustomImage(IDR_THEME_FRAME_OVERLAY
) &&
158 browser_view_
->IsBrowserTypeNormal() &&
159 !browser_view_
->IsOffTheRecord()) {
160 return tp
->GetImageSkiaNamed(ShouldPaintAsActive() ?
161 IDR_THEME_FRAME_OVERLAY
: IDR_THEME_FRAME_OVERLAY_INACTIVE
);
166 int BrowserNonClientFrameView::GetTopAreaHeight() const {
167 gfx::ImageSkia
* frame_image
= GetFrameImage();
168 int top_area_height
= frame_image
->height();
169 if (browser_view_
->IsTabStripVisible()) {
170 top_area_height
= std::max(top_area_height
,
171 GetBoundsForTabStrip(browser_view_
->tabstrip()).bottom());
173 return top_area_height
;
176 void BrowserNonClientFrameView::UpdateAvatar() {
177 if (browser_view()->IsRegularOrGuestSession() && switches::IsNewAvatarMenu())
178 UpdateNewAvatarButtonImpl();
180 UpdateOldAvatarButton();
183 void BrowserNonClientFrameView::UpdateOldAvatarButton() {
184 if (browser_view_
->ShouldShowAvatar()) {
185 if (!avatar_button_
) {
186 #if defined(ENABLE_SUPERVISED_USERS)
187 Profile
* profile
= browser_view_
->browser()->profile();
188 if (profile
->IsSupervised() && !supervised_user_avatar_label_
) {
189 supervised_user_avatar_label_
=
190 new SupervisedUserAvatarLabel(browser_view_
);
191 supervised_user_avatar_label_
->set_id(
192 VIEW_ID_SUPERVISED_USER_AVATAR_LABEL
);
193 AddChildView(supervised_user_avatar_label_
);
196 avatar_button_
= new AvatarMenuButton(
197 browser_view_
->browser(), !browser_view_
->IsRegularOrGuestSession());
198 avatar_button_
->set_id(VIEW_ID_AVATAR_BUTTON
);
199 AddChildView(avatar_button_
);
200 // Invalidate here because adding a child does not invalidate the layout.
202 frame_
->GetRootView()->Layout();
204 } else if (avatar_button_
) {
205 #if defined(ENABLE_SUPERVISED_USERS)
206 // The avatar label can just be there if there is also an avatar button.
207 if (supervised_user_avatar_label_
) {
208 RemoveChildView(supervised_user_avatar_label_
);
209 delete supervised_user_avatar_label_
;
210 supervised_user_avatar_label_
= nullptr;
213 RemoveChildView(avatar_button_
);
214 delete avatar_button_
;
215 avatar_button_
= nullptr;
216 frame_
->GetRootView()->Layout();
220 gfx::Image taskbar_badge_avatar
;
221 bool is_rectangle
= false;
223 // Update the avatar button in the window frame and the taskbar overlay.
224 bool should_show_avatar_menu
=
225 avatar_button_
|| AvatarMenu::ShouldShowAvatarMenu();
227 if (!AvatarMenuButton::GetAvatarImages(
228 browser_view_
->browser()->profile(), should_show_avatar_menu
, &avatar
,
229 &taskbar_badge_avatar
, &is_rectangle
)) {
233 // Disable the menu when we should not show the menu.
234 if (avatar_button_
&& !AvatarMenu::ShouldShowAvatarMenu())
235 avatar_button_
->SetEnabled(false);
237 avatar_button_
->SetAvatarIcon(avatar
, is_rectangle
);
240 void BrowserNonClientFrameView::UpdateNewAvatarButton(
241 views::ButtonListener
* listener
,
242 const NewAvatarButton::AvatarButtonStyle style
) {
243 DCHECK(switches::IsNewAvatarMenu());
244 // This should never be called in incognito mode.
245 DCHECK(browser_view_
->IsRegularOrGuestSession());
247 if (browser_view_
->ShouldShowAvatar()) {
248 if (!new_avatar_button_
) {
250 new NewAvatarButton(listener
, style
, browser_view_
->browser());
251 new_avatar_button_
->set_id(VIEW_ID_NEW_AVATAR_BUTTON
);
252 AddChildView(new_avatar_button_
);
253 frame_
->GetRootView()->Layout();
255 } else if (new_avatar_button_
) {
256 delete new_avatar_button_
;
257 new_avatar_button_
= nullptr;
258 frame_
->GetRootView()->Layout();
262 void BrowserNonClientFrameView::OnProfileAdded(
263 const base::FilePath
& profile_path
) {
264 UpdateTaskbarDecoration();
268 void BrowserNonClientFrameView::OnProfileWasRemoved(
269 const base::FilePath
& profile_path
,
270 const base::string16
& profile_name
) {
271 UpdateTaskbarDecoration();
275 void BrowserNonClientFrameView::OnProfileAvatarChanged(
276 const base::FilePath
& profile_path
) {
277 UpdateTaskbarDecoration();
278 // Profile avatars are only displayed in the old UI or incognito.
279 if ((!browser_view()->IsGuestSession() && browser_view()->IsOffTheRecord()) ||
280 !switches::IsNewAvatarMenu()) {
281 UpdateOldAvatarButton();
285 void BrowserNonClientFrameView::UpdateTaskbarDecoration() {
287 gfx::Image taskbar_badge_avatar
;
289 // Only need to update the taskbar overlay here. If GetAvatarImages()
290 // returns false, don't bother trying to update the taskbar decoration since
291 // the returned images are not initialized. This can happen if the user
292 // deletes the current profile.
293 if (AvatarMenuButton::GetAvatarImages(browser_view_
->browser()->profile(),
294 AvatarMenu::ShouldShowAvatarMenu(),
295 &avatar
, &taskbar_badge_avatar
,
297 // For popups and panels which don't have the avatar button, we still
298 // need to draw the taskbar decoration. Even though we have an icon on the
299 // window's relaunch details, we draw over it because the user may have
300 // pinned the badge-less Chrome shortcut which will cause windows to ignore
301 // the relaunch details.
302 // TODO(calamity): ideally this should not be necessary but due to issues
303 // with the default shortcut being pinned, we add the runtime badge for
304 // safety. See crbug.com/313800.
305 bool show_decoration
= AvatarMenu::ShouldShowAvatarMenu() &&
306 !browser_view_
->browser()->profile()->IsGuestSession();
307 // In tests, make sure that the browser process and profile manager are
308 // valid before using.
309 if (g_browser_process
&& g_browser_process
->profile_manager()) {
310 const ProfileInfoCache
& cache
=
311 g_browser_process
->profile_manager()->GetProfileInfoCache();
312 show_decoration
= show_decoration
&& cache
.GetNumberOfProfiles() > 1;
314 chrome::DrawTaskbarDecoration(frame_
->GetNativeWindow(),
316 ? (taskbar_badge_avatar
.IsEmpty() ? &avatar
: &taskbar_badge_avatar
)