This source file includes following definitions.
- throbber_frame_
- GetBoundsForTabStrip
- GetTopInset
- GetThemeBackgroundXInset
- UpdateThrobber
- GetMinimumSize
- GetBoundsForClientView
- GetWindowBoundsForClientBounds
- NonClientHitTest
- OnPaint
- Layout
- HitTestRect
- ButtonPressed
- FrameBorderThickness
- NonClientBorderThickness
- NonClientTopBorderHeight
- PaintToolbarBackground
- PaintRestoredClientEdge
- LayoutNewStyleAvatar
- LayoutAvatar
- LayoutClientView
- GetClientAreaInsets
- CalculateClientAreaBounds
- StartThrobber
- StopThrobber
- DisplayNextThrobberFrame
- Observe
- InitThrobberIcons
#include "chrome/browser/ui/views/frame/glass_browser_frame_view.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/profile_management_switches.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "grit/ui_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle_win.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/win/hwnd_util.h"
#include "ui/views/window/client_view.h"
HICON GlassBrowserFrameView::throbber_icons_[
GlassBrowserFrameView::kThrobberIconCount];
namespace {
const int kNonClientBorderThickness = 3;
const int kNonClientRestoredExtraThickness = 9;
const int kResizeAreaCornerSize = 16;
const int kAvatarBottomSpacing = 2;
const int kAvatarLeftSpacing = 2;
const int kAvatarRightSpacing = -2;
const int kNewAvatarButtonOffset = 5;
const int kContentEdgeShadowThickness = 2;
const int kTabstripTopShadowThickness = 3;
const int kNewTabCaptionRestoredSpacing = 5;
const int kNewTabCaptionMaximizedSpacing = 16;
const int kTabStripIndent = -6;
}
GlassBrowserFrameView::GlassBrowserFrameView(BrowserFrame* frame,
BrowserView* browser_view)
: BrowserNonClientFrameView(frame, browser_view),
throbber_running_(false),
throbber_frame_(0) {
if (browser_view->ShouldShowWindowIcon())
InitThrobberIcons();
if (browser_view->IsRegularOrGuestSession() &&
switches::IsNewProfileManagement())
UpdateNewStyleAvatarInfo(this, NewAvatarButton::NATIVE_BUTTON);
else
UpdateAvatarInfo();
if (!browser_view->IsOffTheRecord()) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllSources());
}
}
GlassBrowserFrameView::~GlassBrowserFrameView() {
}
gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip(
views::View* tabstrip) const {
int minimize_button_offset =
std::min(frame()->GetMinimizeButtonOffset(), width());
if (new_avatar_button()) {
DCHECK(switches::IsNewProfileManagement());
minimize_button_offset -= new_avatar_button()->width();
}
int tabstrip_x = browser_view()->ShouldShowAvatar() ?
(avatar_bounds_.right() + kAvatarRightSpacing) :
NonClientBorderThickness() + kTabStripIndent;
if (base::i18n::IsRTL()) {
if (!browser_view()->ShouldShowAvatar() && frame()->IsMaximized())
tabstrip_x += avatar_bounds_.x();
else if (browser_view()->IsRegularOrGuestSession() &&
switches::IsNewProfileManagement())
tabstrip_x = width() - minimize_button_offset;
minimize_button_offset = width();
}
int tabstrip_width = minimize_button_offset - tabstrip_x -
(frame()->IsMaximized() ?
kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing);
return gfx::Rect(tabstrip_x, NonClientTopBorderHeight(),
std::max(0, tabstrip_width),
tabstrip->GetPreferredSize().height());
}
int GlassBrowserFrameView::GetTopInset() const {
return GetClientAreaInsets().top();
}
int GlassBrowserFrameView::GetThemeBackgroundXInset() const {
return 0;
}
void GlassBrowserFrameView::UpdateThrobber(bool running) {
if (throbber_running_) {
if (running) {
DisplayNextThrobberFrame();
} else {
StopThrobber();
}
} else if (running) {
StartThrobber();
}
}
gfx::Size GlassBrowserFrameView::GetMinimumSize() {
gfx::Size min_size(browser_view()->GetMinimumSize());
gfx::Insets insets = GetClientAreaInsets();
min_size.Enlarge(insets.width(), insets.height());
min_size.Enlarge(2 * kContentEdgeShadowThickness, 0);
if (browser_view()->IsTabStripVisible()) {
TabStrip* tabstrip = browser_view()->tabstrip();
int min_tabstrip_width = tabstrip->GetMinimumSize().width();
int min_tabstrip_area_width =
width() - GetBoundsForTabStrip(tabstrip).width() + min_tabstrip_width;
min_size.set_width(std::max(min_tabstrip_area_width, min_size.width()));
}
return min_size;
}
gfx::Rect GlassBrowserFrameView::GetBoundsForClientView() const {
return client_view_bounds_;
}
gfx::Rect GlassBrowserFrameView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
HWND hwnd = views::HWNDForWidget(frame());
if (!browser_view()->IsTabStripVisible() && hwnd) {
RECT rect = client_bounds.ToRECT();
AdjustWindowRectEx(&rect, GetWindowLong(hwnd, GWL_STYLE), FALSE,
GetWindowLong(hwnd, GWL_EXSTYLE));
return gfx::Rect(rect);
}
gfx::Insets insets = GetClientAreaInsets();
return gfx::Rect(std::max(0, client_bounds.x() - insets.left()),
std::max(0, client_bounds.y() - insets.top()),
client_bounds.width() + insets.width(),
client_bounds.height() + insets.height());
}
int GlassBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
if (!browser_view()->IsBrowserTypeNormal() || !bounds().Contains(point))
return HTNOWHERE;
if (avatar_button() && avatar_button()->GetMirroredBounds().Contains(point))
return HTCLIENT;
if (new_avatar_button() &&
new_avatar_button()->GetMirroredBounds().Contains(point))
return HTCLIENT;
int frame_component = frame()->client_view()->NonClientHitTest(point);
int nonclient_border_thickness = NonClientBorderThickness();
if (gfx::Rect(nonclient_border_thickness, GetSystemMetrics(SM_CXSIZEFRAME),
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON)).Contains(point))
return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;
if (frame_component != HTNOWHERE)
return frame_component;
int frame_border_thickness = FrameBorderThickness();
int window_component = GetHTComponentForFrame(point, frame_border_thickness,
nonclient_border_thickness, frame_border_thickness,
kResizeAreaCornerSize - frame_border_thickness,
frame()->widget_delegate()->CanResize());
return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
}
void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
if (browser_view()->IsToolbarVisible() &&
browser_view()->toolbar()->ShouldPaintBackground())
PaintToolbarBackground(canvas);
if (!frame()->IsMaximized())
PaintRestoredClientEdge(canvas);
}
void GlassBrowserFrameView::Layout() {
if (browser_view()->IsRegularOrGuestSession() &&
switches::IsNewProfileManagement())
LayoutNewStyleAvatar();
else
LayoutAvatar();
LayoutClientView();
}
bool GlassBrowserFrameView::HitTestRect(const gfx::Rect& rect) const {
bool hit_avatar_button = avatar_button() &&
avatar_button()->GetMirroredBounds().Intersects(rect);
bool hit_new_avatar_button = new_avatar_button() &&
new_avatar_button()->GetMirroredBounds().Intersects(rect);
return hit_avatar_button || hit_new_avatar_button ||
!frame()->client_view()->bounds().Intersects(rect);
}
void GlassBrowserFrameView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == new_avatar_button()) {
browser_view()->ShowAvatarBubbleFromAvatarButton(
BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT);
}
}
int GlassBrowserFrameView::FrameBorderThickness() const {
return (frame()->IsMaximized() || frame()->IsFullscreen()) ?
0 : GetSystemMetrics(SM_CXSIZEFRAME);
}
int GlassBrowserFrameView::NonClientBorderThickness() const {
if (frame()->IsMaximized() || frame()->IsFullscreen())
return 0;
return kNonClientBorderThickness;
}
int GlassBrowserFrameView::NonClientTopBorderHeight() const {
if (frame()->IsFullscreen())
return 0;
return gfx::win::GetSystemMetricsInDIP(SM_CYSIZEFRAME) +
(!frame()->ShouldLeaveOffsetNearTopBorder() ?
-kTabstripTopShadowThickness : kNonClientRestoredExtraThickness);
}
void GlassBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
ui::ThemeProvider* tp = GetThemeProvider();
gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
gfx::Point toolbar_origin(toolbar_bounds.origin());
View::ConvertPointToTarget(browser_view(), this, &toolbar_origin);
toolbar_bounds.set_origin(toolbar_origin);
int x = toolbar_bounds.x();
int w = toolbar_bounds.width();
int left_x = x - kContentEdgeShadowThickness;
gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
gfx::ImageSkia* toolbar_left = tp->GetImageSkiaNamed(
IDR_CONTENT_TOP_LEFT_CORNER);
gfx::ImageSkia* toolbar_center = tp->GetImageSkiaNamed(
IDR_CONTENT_TOP_CENTER);
int y = toolbar_bounds.y();
int dest_y = browser_view()->IsTabStripVisible()
? y + (kFrameShadowThickness * 2)
: y;
canvas->TileImageInt(*theme_toolbar,
x + GetThemeBackgroundXInset(),
dest_y - GetTopInset(), x,
dest_y, w, theme_toolbar->height());
if (browser_view()->IsTabStripVisible()) {
gfx::ImageSkia* toolbar_left_mask =
tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK);
gfx::ImageSkia* toolbar_right_mask =
tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
canvas->DrawImageInt(*toolbar_left_mask, left_x, y, paint);
int right_x =
x + w + kContentEdgeShadowThickness - toolbar_right_mask->width();
canvas->DrawImageInt(*toolbar_right_mask, right_x, y, paint);
canvas->DrawImageInt(*toolbar_left, left_x, y);
canvas->TileImageInt(*toolbar_center, left_x + toolbar_left->width(), y,
right_x - (left_x + toolbar_left->width()), toolbar_center->height());
canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER),
right_x, y);
}
canvas->FillRect(
gfx::Rect(x + kClientEdgeThickness,
toolbar_bounds.bottom() - kClientEdgeThickness,
w - (2 * kClientEdgeThickness),
kClientEdgeThickness),
ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
}
void GlassBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
ui::ThemeProvider* tp = GetThemeProvider();
gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height());
int client_area_top = frame()->client_view()->y() +
browser_view()->GetToolbarBounds().y() +
tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height();
int client_area_bottom =
std::max(client_area_top, height() - NonClientBorderThickness());
int client_area_height = client_area_bottom - client_area_top;
gfx::ImageSkia* right = tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
right->width(), client_area_height);
canvas->DrawImageInt(
*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER),
client_area_bounds.right(), client_area_bottom);
gfx::ImageSkia* bottom = tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
canvas->TileImageInt(*bottom, client_area_bounds.x(),
client_area_bottom, client_area_bounds.width(),
bottom->height());
gfx::ImageSkia* bottom_left =
tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
canvas->DrawImageInt(*bottom_left,
client_area_bounds.x() - bottom_left->width(), client_area_bottom);
gfx::ImageSkia* left = tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE);
canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
client_area_top, left->width(), client_area_height);
SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
canvas->FillRect(gfx::Rect(client_area_bounds.x() - kClientEdgeThickness,
client_area_top, kClientEdgeThickness,
client_area_bottom + kClientEdgeThickness - client_area_top),
toolbar_color);
canvas->FillRect(gfx::Rect(client_area_bounds.x(), client_area_bottom,
client_area_bounds.width(), kClientEdgeThickness),
toolbar_color);
canvas->FillRect(gfx::Rect(client_area_bounds.right(), client_area_top,
kClientEdgeThickness,
client_area_bottom + kClientEdgeThickness - client_area_top),
toolbar_color);
}
void GlassBrowserFrameView::LayoutNewStyleAvatar() {
DCHECK(switches::IsNewProfileManagement());
if (!new_avatar_button())
return;
gfx::Size label_size = new_avatar_button()->GetPreferredSize();
int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
int button_x = frame()->GetMinimizeButtonOffset() -
kNewAvatarButtonOffset - label_size.width();
if (base::i18n::IsRTL())
button_x = width() - frame()->GetMinimizeButtonOffset() +
kNewAvatarButtonOffset;
int button_y = frame()->IsMaximized() ? NonClientTopBorderHeight() : 1;
new_avatar_button()->SetBounds(
button_x,
button_y,
label_size.width(),
button_y + gfx::win::GetSystemMetricsInDIP(SM_CXMENUSIZE));
}
void GlassBrowserFrameView::LayoutAvatar() {
gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon();
int avatar_x = NonClientBorderThickness() + kAvatarLeftSpacing;
if (base::i18n::IsRTL())
avatar_x += width() - frame()->GetMinimizeButtonOffset();
int avatar_bottom = GetTopInset() +
browser_view()->GetTabStripHeight() - kAvatarBottomSpacing;
int avatar_restored_y = avatar_bottom - incognito_icon.height();
int avatar_y = frame()->IsMaximized() ?
(NonClientTopBorderHeight() + kTabstripTopShadowThickness) :
avatar_restored_y;
avatar_bounds_.SetRect(avatar_x, avatar_y, incognito_icon.width(),
browser_view()->ShouldShowAvatar() ? (avatar_bottom - avatar_y) : 0);
if (avatar_button())
avatar_button()->SetBoundsRect(avatar_bounds_);
}
void GlassBrowserFrameView::LayoutClientView() {
client_view_bounds_ = CalculateClientAreaBounds(width(), height());
}
gfx::Insets GlassBrowserFrameView::GetClientAreaInsets() const {
if (!browser_view()->IsTabStripVisible())
return gfx::Insets();
const int top_height = NonClientTopBorderHeight();
const int border_thickness = NonClientBorderThickness();
return gfx::Insets(top_height,
border_thickness,
border_thickness,
border_thickness);
}
gfx::Rect GlassBrowserFrameView::CalculateClientAreaBounds(int width,
int height) const {
gfx::Rect bounds(0, 0, width, height);
bounds.Inset(GetClientAreaInsets());
return bounds;
}
void GlassBrowserFrameView::StartThrobber() {
if (!throbber_running_) {
throbber_running_ = true;
throbber_frame_ = 0;
InitThrobberIcons();
SendMessage(views::HWNDForWidget(frame()), WM_SETICON,
static_cast<WPARAM>(ICON_SMALL),
reinterpret_cast<LPARAM>(throbber_icons_[throbber_frame_]));
}
}
void GlassBrowserFrameView::StopThrobber() {
if (throbber_running_) {
throbber_running_ = false;
HICON frame_icon = NULL;
if (browser_view()->ShouldShowWindowIcon()) {
gfx::ImageSkia icon = browser_view()->GetWindowIcon();
if (!icon.isNull())
frame_icon = IconUtil::CreateHICONFromSkBitmap(*icon.bitmap());
}
if (!frame_icon) {
frame_icon = reinterpret_cast<HICON>(GetClassLongPtr(
views::HWNDForWidget(frame()), GCLP_HICONSM));
}
SendMessage(views::HWNDForWidget(frame()), WM_SETICON,
static_cast<WPARAM>(ICON_SMALL),
reinterpret_cast<LPARAM>(frame_icon));
}
}
void GlassBrowserFrameView::DisplayNextThrobberFrame() {
throbber_frame_ = (throbber_frame_ + 1) % kThrobberIconCount;
SendMessage(views::HWNDForWidget(frame()), WM_SETICON,
static_cast<WPARAM>(ICON_SMALL),
reinterpret_cast<LPARAM>(throbber_icons_[throbber_frame_]));
}
void GlassBrowserFrameView::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
if (browser_view()->IsRegularOrGuestSession() &&
switches::IsNewProfileManagement())
UpdateNewStyleAvatarInfo(this, NewAvatarButton::NATIVE_BUTTON);
else
UpdateAvatarInfo();
break;
default:
NOTREACHED() << "Got a notification we didn't register for!";
break;
}
}
void GlassBrowserFrameView::InitThrobberIcons() {
static bool initialized = false;
if (!initialized) {
for (int i = 0; i < kThrobberIconCount; ++i) {
throbber_icons_[i] =
ui::LoadThemeIconFromResourcesDataDLL(IDI_THROBBER_01 + i);
DCHECK(throbber_icons_[i]);
}
initialized = true;
}
}