This source file includes following definitions.
- OnMouseMoveEvent
- GdkColorToHSL
- PickLuminosityContrastingColor
- browser_
- Build
- theme_service_
- Init
- BuildButtons
- BuildButton
- GetButtonHBox
- CreateTitlebarButton
- GetButtonResources
- UpdateButtonBackground
- UpdateCustomFrame
- UpdateTitleAndIcon
- UpdateThrobber
- UpdateTitlebarAlignment
- UpdateTextColor
- UpdateAvatarLabel
- UpdateAvatar
- MaximizeButtonClicked
- UpdateMaximizeRestoreVisibility
- OnWindowStateChanged
- OnScroll
- OnButtonClicked
- OnFaviconMenuButtonPressed
- OnAvatarLabelButtonPressed
- ShowContextMenu
- IsCommandIdEnabled
- IsCommandIdChecked
- ExecuteCommand
- GetAcceleratorForCommandId
- Observe
- ActiveWindowChanged
- ShouldDisplayAvatar
- IsOffTheRecord
#include "chrome/browser/ui/gtk/browser_titlebar.h"
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/memory/singleton.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/gtk/accelerators_gtk.h"
#include "chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h"
#include "chrome/browser/ui/gtk/avatar_menu_button_gtk.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/custom_button.h"
#if defined(USE_GCONF)
#include "chrome/browser/ui/gtk/gconf_titlebar_listener.h"
#endif
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/menu_gtk.h"
#include "chrome/browser/ui/gtk/nine_box.h"
#include "chrome/browser/ui/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/ui/gtk/unity_service.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "grit/ui_resources.h"
#include "ui/base/gtk/gtk_hig_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/x/active_window_watcher_x.h"
#include "ui/gfx/image/image.h"
using content::WebContents;
namespace {
const int kTitlebarHeight = 14;
const int kTabOuterThickness = 1;
const int kNormalVerticalOffset = kTitlebarHeight + kTabOuterThickness;
const int kShowWindowDecorationsCommand = 200;
const int kAvatarBottomSpacing = 1;
const int kAvatarSideSpacing = 2;
const int kIconTitleSpacing = 4;
const int kAppModePaddingTop = 5;
const int kAppModePaddingBottom = 4;
const int kAppModePaddingLeft = 2;
const int kTabStripLeftPadding = 1;
const int kButtonSpacing = 2;
const int kButtonOuterPadding = 2;
const int kMaximizedTabstripPadding = 16;
gboolean OnMouseMoveEvent(GtkWidget* widget, GdkEventMotion* event,
BrowserWindowGtk* browser_window) {
browser_window->ResetCustomFrameCursor();
return TRUE;
}
color_utils::HSL GdkColorToHSL(const GdkColor* color) {
color_utils::HSL hsl;
color_utils::SkColorToHSL(SkColorSetRGB(color->red >> 8,
color->green >> 8,
color->blue >> 8), &hsl);
return hsl;
}
GdkColor PickLuminosityContrastingColor(const GdkColor* base,
const GdkColor* one,
const GdkColor* two) {
color_utils::HSL baseHSL = GdkColorToHSL(base);
color_utils::HSL oneHSL = GdkColorToHSL(one);
color_utils::HSL twoHSL = GdkColorToHSL(two);
double one_difference = fabs(baseHSL.l - oneHSL.l);
double two_difference = fabs(baseHSL.l - twoHSL.l);
if (two_difference > one_difference + 0.1)
return *two;
else
return *one;
}
}
class PopupPageMenuModel : public ui::SimpleMenuModel {
public:
PopupPageMenuModel(ui::SimpleMenuModel::Delegate* delegate, Browser* browser);
virtual ~PopupPageMenuModel() { }
private:
void Build();
scoped_ptr<ZoomMenuModel> zoom_menu_model_;
scoped_ptr<EncodingMenuModel> encoding_menu_model_;
Browser* browser_;
DISALLOW_COPY_AND_ASSIGN(PopupPageMenuModel);
};
PopupPageMenuModel::PopupPageMenuModel(
ui::SimpleMenuModel::Delegate* delegate,
Browser* browser)
: ui::SimpleMenuModel(delegate), browser_(browser) {
Build();
}
void PopupPageMenuModel::Build() {
AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
AddItemWithStringId(IDC_RELOAD, IDS_APP_MENU_RELOAD);
AddSeparator(ui::NORMAL_SEPARATOR);
AddItemWithStringId(IDC_SHOW_AS_TAB, IDS_SHOW_AS_TAB);
AddSeparator(ui::NORMAL_SEPARATOR);
AddItemWithStringId(IDC_CUT, IDS_CUT);
AddItemWithStringId(IDC_COPY, IDS_COPY);
AddItemWithStringId(IDC_PASTE, IDS_PASTE);
AddSeparator(ui::NORMAL_SEPARATOR);
AddItemWithStringId(IDC_FIND, IDS_FIND);
AddItemWithStringId(IDC_PRINT, IDS_PRINT);
zoom_menu_model_.reset(new ZoomMenuModel(delegate()));
AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_ZOOM_MENU, zoom_menu_model_.get());
encoding_menu_model_.reset(new EncodingMenuModel(browser_));
AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
encoding_menu_model_.get());
AddSeparator(ui::NORMAL_SEPARATOR);
AddItemWithStringId(IDC_CLOSE_WINDOW, IDS_CLOSE);
}
const char BrowserTitlebar::kDefaultButtonString[] = ":minimize,maximize,close";
BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window,
GtkWindow* window)
: browser_window_(browser_window),
window_(window),
container_(NULL),
container_hbox_(NULL),
titlebar_left_buttons_vbox_(NULL),
titlebar_right_buttons_vbox_(NULL),
titlebar_left_buttons_hbox_(NULL),
titlebar_right_buttons_hbox_(NULL),
titlebar_left_avatar_frame_(NULL),
titlebar_right_avatar_frame_(NULL),
titlebar_left_label_frame_(NULL),
titlebar_right_label_frame_(NULL),
avatar_(NULL),
avatar_label_(NULL),
avatar_label_bg_(NULL),
top_padding_left_(NULL),
top_padding_right_(NULL),
titlebar_alignment_(NULL),
app_mode_favicon_(NULL),
app_mode_title_(NULL),
using_custom_frame_(false),
window_has_focus_(false),
display_avatar_on_left_(false),
theme_service_(NULL) {
}
void BrowserTitlebar::Init() {
container_hbox_ = gtk_hbox_new(FALSE, 0);
container_ = gtk_event_box_new();
gtk_widget_set_name(container_, "chrome-browser-titlebar");
gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE);
gtk_container_add(GTK_CONTAINER(container_), container_hbox_);
g_signal_connect(container_, "scroll-event", G_CALLBACK(OnScrollThunk), this);
g_signal_connect(window_, "window-state-event",
G_CALLBACK(OnWindowStateChangedThunk), this);
titlebar_left_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_buttons_vbox_,
FALSE, FALSE, 0);
titlebar_left_avatar_frame_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
gtk_widget_set_no_show_all(titlebar_left_avatar_frame_, TRUE);
gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_left_avatar_frame_), 0,
kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_avatar_frame_,
FALSE, FALSE, 0);
titlebar_left_label_frame_ = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
gtk_widget_set_no_show_all(titlebar_left_label_frame_, TRUE);
gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_left_label_frame_), 0,
kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_label_frame_,
FALSE, FALSE, 0);
titlebar_right_avatar_frame_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
gtk_widget_set_no_show_all(titlebar_right_avatar_frame_, TRUE);
gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_right_avatar_frame_), 0,
kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_avatar_frame_,
FALSE, FALSE, 0);
titlebar_right_label_frame_ = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
gtk_widget_set_no_show_all(titlebar_right_label_frame_, TRUE);
gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_right_label_frame_), 0,
kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_label_frame_,
FALSE, FALSE, 0);
titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_buttons_vbox_,
FALSE, FALSE, 0);
avatar_button_.reset(new AvatarMenuButtonGtk(browser_window_->browser()));
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllSources());
#if defined(USE_GCONF)
GConfTitlebarListener::GetInstance()->SetTitlebarButtons(this);
#else
BuildButtons(kDefaultButtonString);
#endif
UpdateAvatar();
titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
if (browser_window_->browser()->is_type_tabbed()) {
gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE,
TRUE, 0);
gtk_container_add(GTK_CONTAINER(titlebar_alignment_),
browser_window_->tabstrip()->widget());
} else {
gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE,
TRUE, 0);
GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing);
gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox);
gtk_box_pack_start(GTK_BOX(app_mode_hbox),
browser_window_->tabstrip()->widget(), FALSE, FALSE, 0);
GtkWidget* favicon_event_box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(favicon_event_box), FALSE);
g_signal_connect(favicon_event_box, "button-press-event",
G_CALLBACK(OnFaviconMenuButtonPressedThunk), this);
gtk_box_pack_start(GTK_BOX(app_mode_hbox), favicon_event_box, FALSE,
FALSE, 0);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
app_mode_favicon_ = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed(
IDR_PRODUCT_LOGO_16, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf());
g_object_set_data(G_OBJECT(app_mode_favicon_), "left-align-popup",
reinterpret_cast<void*>(true));
gtk_container_add(GTK_CONTAINER(favicon_event_box), app_mode_favicon_);
app_mode_title_ = gtk_label_new(NULL);
gtk_label_set_ellipsize(GTK_LABEL(app_mode_title_), PANGO_ELLIPSIZE_END);
gtk_misc_set_alignment(GTK_MISC(app_mode_title_), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_title_, TRUE, TRUE,
0);
UpdateTitleAndIcon();
}
theme_service_ = GtkThemeService::GetFrom(
browser_window_->browser()->profile());
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
content::Source<ThemeService>(theme_service_));
theme_service_->InitThemesFor(this);
gtk_widget_show_all(container_);
ui::ActiveWindowWatcherX::AddObserver(this);
}
BrowserTitlebar::~BrowserTitlebar() {
ui::ActiveWindowWatcherX::RemoveObserver(this);
#if defined(USE_GCONF)
GConfTitlebarListener::GetInstance()->RemoveObserver(this);
#endif
}
void BrowserTitlebar::BuildButtons(const std::string& button_string) {
close_button_.reset();
restore_button_.reset();
maximize_button_.reset();
minimize_button_.reset();
gtk_util::RemoveAllChildren(titlebar_left_buttons_vbox_);
gtk_util::RemoveAllChildren(titlebar_right_buttons_vbox_);
titlebar_left_buttons_hbox_ = NULL;
titlebar_right_buttons_hbox_ = NULL;
top_padding_left_ = NULL;
top_padding_right_ = NULL;
bool left_side = true;
base::StringTokenizer tokenizer(button_string, ":,");
tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
int left_count = 0;
int right_count = 0;
while (tokenizer.GetNext()) {
if (tokenizer.token_is_delim()) {
if (*tokenizer.token_begin() == ':')
left_side = false;
} else {
base::StringPiece token = tokenizer.token_piece();
if (BuildButton(token.as_string(), left_side))
(left_side ? left_count : right_count)++;
}
}
display_avatar_on_left_ = right_count > left_count;
if (using_custom_frame_) {
gtk_widget_show_all(titlebar_left_buttons_vbox_);
gtk_widget_show_all(titlebar_right_buttons_vbox_);
}
UpdateMaximizeRestoreVisibility();
}
bool BrowserTitlebar::BuildButton(const std::string& button_token,
bool left_side) {
if (button_token == "minimize") {
minimize_button_.reset(CreateTitlebarButton("minimize", left_side));
gtk_widget_size_request(minimize_button_->widget(),
&minimize_button_req_);
return true;
} else if (button_token == "maximize") {
restore_button_.reset(CreateTitlebarButton("unmaximize", left_side));
maximize_button_.reset(CreateTitlebarButton("maximize", left_side));
gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(),
true, true, true);
gtk_widget_size_request(restore_button_->widget(),
&restore_button_req_);
return true;
} else if (button_token == "close") {
close_button_.reset(CreateTitlebarButton("close", left_side));
close_button_->set_flipped(left_side);
gtk_widget_size_request(close_button_->widget(), &close_button_req_);
return true;
}
return false;
}
GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) {
if (left_side && titlebar_left_buttons_hbox_)
return titlebar_left_buttons_hbox_;
else if (!left_side && titlebar_right_buttons_hbox_)
return titlebar_right_buttons_hbox_;
GtkWidget* vbox = left_side ? titlebar_left_buttons_vbox_ :
titlebar_right_buttons_vbox_;
GtkWidget* top_padding = gtk_fixed_new();
gtk_widget_set_size_request(top_padding, -1, kButtonOuterPadding);
gtk_box_pack_start(GTK_BOX(vbox), top_padding, FALSE, FALSE, 0);
GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing);
gtk_box_pack_start(GTK_BOX(vbox), buttons_hbox, FALSE, FALSE, 0);
if (left_side) {
titlebar_left_buttons_hbox_ = buttons_hbox;
top_padding_left_ = top_padding;
} else {
titlebar_right_buttons_hbox_ = buttons_hbox;
top_padding_right_ = top_padding;
}
return buttons_hbox;
}
CustomDrawButton* BrowserTitlebar::CreateTitlebarButton(
const std::string& button_name, bool left_side) {
int normal_image_id;
int pressed_image_id;
int hover_image_id;
int tooltip_id;
GetButtonResources(button_name, &normal_image_id, &pressed_image_id,
&hover_image_id, &tooltip_id);
CustomDrawButton* button = new CustomDrawButton(normal_image_id,
pressed_image_id,
hover_image_id,
0);
gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK);
g_signal_connect(button->widget(), "clicked",
G_CALLBACK(OnButtonClickedThunk), this);
g_signal_connect(button->widget(), "motion-notify-event",
G_CALLBACK(OnMouseMoveEvent), browser_window_);
std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip_id);
gtk_widget_set_tooltip_text(button->widget(),
localized_tooltip.c_str());
GtkWidget* box = GetButtonHBox(left_side);
gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0);
return button;
}
void BrowserTitlebar::GetButtonResources(const std::string& button_name,
int* normal_image_id,
int* pressed_image_id,
int* hover_image_id,
int* tooltip_id) const {
if (button_name == "close") {
*normal_image_id = IDR_CLOSE;
*pressed_image_id = IDR_CLOSE_P;
*hover_image_id = IDR_CLOSE_H;
*tooltip_id = IDS_XPFRAME_CLOSE_TOOLTIP;
} else if (button_name == "minimize") {
*normal_image_id = IDR_MINIMIZE;
*pressed_image_id = IDR_MINIMIZE_P;
*hover_image_id = IDR_MINIMIZE_H;
*tooltip_id = IDS_XPFRAME_MINIMIZE_TOOLTIP;
} else if (button_name == "maximize") {
*normal_image_id = IDR_MAXIMIZE;
*pressed_image_id = IDR_MAXIMIZE_P;
*hover_image_id = IDR_MAXIMIZE_H;
*tooltip_id = IDS_XPFRAME_MAXIMIZE_TOOLTIP;
} else if (button_name == "unmaximize") {
*normal_image_id = IDR_RESTORE;
*pressed_image_id = IDR_RESTORE_P;
*hover_image_id = IDR_RESTORE_H;
*tooltip_id = IDS_XPFRAME_RESTORE_TOOLTIP;
}
}
void BrowserTitlebar::UpdateButtonBackground(CustomDrawButton* button) {
SkColor color = theme_service_->GetColor(
ThemeProperties::COLOR_BUTTON_BACKGROUND);
SkBitmap background = theme_service_->GetImageNamed(
IDR_THEME_WINDOW_CONTROL_BACKGROUND).AsBitmap();
SkBitmap mask;
mask.setConfig(SkBitmap::kARGB_8888_Config,
button->SurfaceWidth(), button->SurfaceHeight(), 0);
mask.allocPixels();
mask.eraseColor(SK_ColorBLACK);
button->SetBackground(color, background, mask);
}
void BrowserTitlebar::UpdateCustomFrame(bool use_custom_frame) {
using_custom_frame_ = use_custom_frame;
if (!use_custom_frame ||
(browser_window_->IsMaximized() && unity::IsRunning())) {
if (titlebar_left_buttons_vbox_)
gtk_widget_hide(titlebar_left_buttons_vbox_);
if (titlebar_right_buttons_vbox_)
gtk_widget_hide(titlebar_right_buttons_vbox_);
} else {
if (titlebar_left_buttons_vbox_)
gtk_widget_show_all(titlebar_left_buttons_vbox_);
if (titlebar_right_buttons_vbox_)
gtk_widget_show_all(titlebar_right_buttons_vbox_);
}
UpdateTitlebarAlignment();
UpdateMaximizeRestoreVisibility();
}
void BrowserTitlebar::UpdateTitleAndIcon() {
if (!app_mode_title_)
return;
base::string16 title =
browser_window_->browser()->GetWindowTitleForCurrentTab();
gtk_label_set_text(GTK_LABEL(app_mode_title_),
base::UTF16ToUTF8(title).c_str());
if (browser_window_->browser()->is_app()) {
switch (browser_window_->browser()->type()) {
case Browser::TYPE_POPUP: {
Profile* profile = browser_window_->browser()->profile();
gfx::Image icon = browser_window_->browser()->GetCurrentPageIcon();
if (icon.IsEmpty()) {
gtk_util::SetWindowIcon(window_, profile);
} else {
gtk_util::SetWindowIcon(window_, profile, icon.ToGdkPixbuf());
}
break;
}
case Browser::TYPE_TABBED: {
NOTREACHED() << "We should never have a tabbed app window.";
break;
}
}
}
}
void BrowserTitlebar::UpdateThrobber(WebContents* web_contents) {
DCHECK(app_mode_favicon_);
if (web_contents && web_contents->IsLoading()) {
GdkPixbuf* icon_pixbuf =
throbber_.GetNextFrame(web_contents->IsWaitingForResponse());
gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf);
} else {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
if ((browser_window_->browser()->is_app() &&
!browser_window_->browser()->is_type_tabbed()) ||
browser_window_->browser()->is_type_popup()) {
gfx::Image icon = browser_window_->browser()->GetCurrentPageIcon();
if (icon.IsEmpty()) {
gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf());
} else {
gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
icon.ToGdkPixbuf());
}
} else {
gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf());
}
throbber_.Reset();
}
}
void BrowserTitlebar::UpdateTitlebarAlignment() {
if (browser_window_->browser()->is_type_tabbed()) {
int top_padding = 0;
int side_padding = 0;
int vertical_offset = kNormalVerticalOffset;
if (using_custom_frame_) {
if (!browser_window_->IsMaximized()) {
top_padding = kTitlebarHeight;
} else if (using_custom_frame_ && browser_window_->IsMaximized()) {
vertical_offset = 0;
if (!unity::IsRunning())
side_padding = kMaximizedTabstripPadding;
}
}
int right_padding = 0;
int left_padding = kTabStripLeftPadding;
if (titlebar_right_buttons_hbox_)
right_padding = side_padding;
if (titlebar_left_buttons_hbox_)
left_padding = side_padding;
gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
top_padding, 0,
left_padding, right_padding);
browser_window_->tabstrip()->SetVerticalOffset(vertical_offset);
} else {
if (using_custom_frame_ && !browser_window_->IsFullscreen()) {
gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
kAppModePaddingTop, kAppModePaddingBottom, kAppModePaddingLeft, 0);
gtk_widget_show(titlebar_alignment_);
} else {
gtk_widget_hide(titlebar_alignment_);
}
}
GtkRequisition close_button_req = close_button_req_;
GtkRequisition minimize_button_req = minimize_button_req_;
GtkRequisition restore_button_req = restore_button_req_;
if (using_custom_frame_ && browser_window_->IsMaximized()) {
close_button_req.width += kButtonOuterPadding;
close_button_req.height += kButtonOuterPadding;
minimize_button_req.height += kButtonOuterPadding;
restore_button_req.height += kButtonOuterPadding;
if (top_padding_left_)
gtk_widget_hide(top_padding_left_);
if (top_padding_right_)
gtk_widget_hide(top_padding_right_);
} else {
if (top_padding_left_)
gtk_widget_show(top_padding_left_);
if (top_padding_right_)
gtk_widget_show(top_padding_right_);
}
if (close_button_.get()) {
gtk_widget_set_size_request(close_button_->widget(),
close_button_req.width,
close_button_req.height);
}
if (minimize_button_.get()) {
gtk_widget_set_size_request(minimize_button_->widget(),
minimize_button_req.width,
minimize_button_req.height);
}
if (maximize_button_.get()) {
gtk_widget_set_size_request(restore_button_->widget(),
restore_button_req.width,
restore_button_req.height);
}
}
void BrowserTitlebar::UpdateTextColor() {
if (!app_mode_title_)
return;
if (theme_service_ && theme_service_->UsingNativeTheme()) {
GdkColor frame_color;
if (window_has_focus_) {
frame_color = theme_service_->GetGdkColor(
ThemeProperties::COLOR_FRAME);
} else {
frame_color = theme_service_->GetGdkColor(
ThemeProperties::COLOR_FRAME_INACTIVE);
}
GdkColor text_color = PickLuminosityContrastingColor(
&frame_color, &ui::kGdkWhite, &ui::kGdkBlack);
gtk_util::SetLabelColor(app_mode_title_, &text_color);
} else {
gtk_util::SetLabelColor(app_mode_title_, &ui::kGdkWhite);
}
}
void BrowserTitlebar::UpdateAvatarLabel() {
if (theme_service_ && avatar_label_) {
GdkColor text_color =
theme_service_->GetGdkColor(ThemeProperties::COLOR_MANAGED_USER_LABEL);
GdkColor label_background = theme_service_->GetGdkColor(
ThemeProperties::COLOR_MANAGED_USER_LABEL_BACKGROUND);
gtk_util::SetLabelColor(avatar_label_, &text_color);
gtk_widget_modify_bg(
GTK_WIDGET(avatar_label_bg_), GTK_STATE_NORMAL, &label_background);
char* markup = g_markup_printf_escaped(
"<span size='small'>%s</span>",
l10n_util::GetStringUTF8(IDS_MANAGED_USER_AVATAR_LABEL).c_str());
gtk_label_set_markup(GTK_LABEL(avatar_label_), markup);
g_free(markup);
}
}
void BrowserTitlebar::UpdateAvatar() {
gtk_util::RemoveAllChildren(titlebar_left_avatar_frame_);
gtk_util::RemoveAllChildren(titlebar_right_avatar_frame_);
gtk_util::RemoveAllChildren(titlebar_left_label_frame_);
gtk_util::RemoveAllChildren(titlebar_right_label_frame_);
if (!ShouldDisplayAvatar())
return;
if (!avatar_) {
if (IsOffTheRecord()) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
gfx::Image avatar_image =
rb.GetNativeImageNamed(IDR_OTR_ICON, ui::ResourceBundle::RTL_ENABLED);
avatar_ = gtk_image_new_from_pixbuf(avatar_image.ToGdkPixbuf());
gtk_misc_set_alignment(GTK_MISC(avatar_), 0.0, 1.0);
gtk_widget_set_size_request(avatar_, -1, 0);
} else {
avatar_ = avatar_button_->widget();
}
}
gtk_widget_show_all(avatar_);
Profile* profile = browser_window_->browser()->profile();
if (profile->IsManaged()) {
avatar_label_ = gtk_label_new(NULL);
gtk_misc_set_padding(GTK_MISC(avatar_label_), 10, 2);
avatar_label_bg_ = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(avatar_label_bg_), avatar_label_);
g_signal_connect(avatar_label_bg_, "button-press-event",
G_CALLBACK(OnAvatarLabelButtonPressedThunk), this);
UpdateAvatarLabel();
gtk_widget_show(avatar_label_bg_);
gtk_widget_show(avatar_label_);
if (display_avatar_on_left_) {
gtk_container_add(GTK_CONTAINER(titlebar_left_label_frame_),
avatar_label_bg_);
gtk_widget_show(titlebar_left_label_frame_);
gtk_widget_hide(titlebar_right_label_frame_);
} else {
gtk_container_add(GTK_CONTAINER(titlebar_right_label_frame_),
avatar_label_bg_);
gtk_widget_show(titlebar_right_label_frame_);
gtk_widget_hide(titlebar_left_label_frame_);
}
}
if (display_avatar_on_left_) {
gtk_container_add(GTK_CONTAINER(titlebar_left_avatar_frame_), avatar_);
gtk_widget_show(titlebar_left_avatar_frame_);
gtk_widget_hide(titlebar_right_avatar_frame_);
} else {
gtk_container_add(GTK_CONTAINER(titlebar_right_avatar_frame_), avatar_);
gtk_widget_show(titlebar_right_avatar_frame_);
gtk_widget_hide(titlebar_left_avatar_frame_);
}
if (IsOffTheRecord())
return;
bool is_gaia_picture = false;
gfx::Image avatar;
ProfileInfoCache& cache =
g_browser_process->profile_manager()->GetProfileInfoCache();
size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
if (index == std::string::npos)
return;
is_gaia_picture =
cache.IsUsingGAIAPictureOfProfileAtIndex(index) &&
cache.GetGAIAPictureOfProfileAtIndex(index);
avatar = cache.GetAvatarIconOfProfileAtIndex(index);
avatar_button_->SetIcon(avatar, is_gaia_picture);
avatar_button_->set_menu_frame_style(display_avatar_on_left_ ?
BubbleGtk::ANCHOR_TOP_LEFT : BubbleGtk::ANCHOR_TOP_RIGHT);
}
void BrowserTitlebar::MaximizeButtonClicked() {
GdkEvent* event = gtk_get_current_event();
if (event->button.button == 1) {
gtk_window_maximize(window_);
} else {
GtkWidget* widget = GTK_WIDGET(window_);
GdkScreen* screen = gtk_widget_get_screen(widget);
gint monitor = gdk_screen_get_monitor_at_window(
screen, gtk_widget_get_window(widget));
GdkRectangle screen_rect;
gdk_screen_get_monitor_geometry(screen, monitor, &screen_rect);
gint x, y;
gtk_window_get_position(window_, &x, &y);
GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);
gint width = allocation.width;
gint height = allocation.height;
if (event->button.button == 3) {
x = 0;
width = screen_rect.width;
} else if (event->button.button == 2) {
y = 0;
height = screen_rect.height;
}
browser_window_->SetBounds(gfx::Rect(x, y, width, height));
}
gdk_event_free(event);
}
void BrowserTitlebar::UpdateMaximizeRestoreVisibility() {
if (maximize_button_.get()) {
if (browser_window_->IsMaximized()) {
gtk_widget_hide(maximize_button_->widget());
gtk_widget_show(restore_button_->widget());
} else {
gtk_widget_hide(restore_button_->widget());
gtk_widget_show(maximize_button_->widget());
}
}
}
gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window,
GdkEventWindowState* event) {
UpdateMaximizeRestoreVisibility();
UpdateTitlebarAlignment();
UpdateTextColor();
return FALSE;
}
gboolean BrowserTitlebar::OnScroll(GtkWidget* widget, GdkEventScroll* event) {
Browser* browser = browser_window_->browser();
int index = browser->tab_strip_model()->active_index();
if (event->direction == GDK_SCROLL_LEFT ||
event->direction == GDK_SCROLL_UP) {
if (index != 0)
chrome::SelectPreviousTab(browser);
} else if (index + 1 < browser->tab_strip_model()->count()) {
chrome::SelectNextTab(browser);
}
return TRUE;
}
void BrowserTitlebar::OnButtonClicked(GtkWidget* button) {
if (close_button_.get() && close_button_->widget() == button) {
browser_window_->Close();
} else if (restore_button_.get() && restore_button_->widget() == button) {
browser_window_->UnMaximize();
} else if (maximize_button_.get() && maximize_button_->widget() == button) {
MaximizeButtonClicked();
} else if (minimize_button_.get() && minimize_button_->widget() == button) {
gtk_window_iconify(window_);
}
}
gboolean BrowserTitlebar::OnFaviconMenuButtonPressed(GtkWidget* widget,
GdkEventButton* event) {
if (event->button != 1)
return FALSE;
if (!favicon_menu_model_.get()) {
favicon_menu_model_.reset(
new PopupPageMenuModel(this, browser_window_->browser()));
favicon_menu_.reset(new MenuGtk(NULL, favicon_menu_model_.get()));
}
favicon_menu_->PopupForWidget(app_mode_favicon_, event->button, event->time);
return TRUE;
}
gboolean BrowserTitlebar::OnAvatarLabelButtonPressed(GtkWidget* widget,
GdkEventButton* event) {
if (event->button != 1)
return FALSE;
gfx::Rect rect = gtk_util::WidgetBounds(widget);
rect.set_x(event->x);
rect.set_width(0);
new AvatarMenuBubbleGtk(
browser_window_->browser(), widget, BubbleGtk::ANCHOR_TOP_RIGHT, &rect);
return TRUE;
}
void BrowserTitlebar::ShowContextMenu(GdkEventButton* event) {
if (!context_menu_.get()) {
context_menu_model_.reset(new ContextMenuModel(this));
context_menu_.reset(new MenuGtk(NULL, context_menu_model_.get()));
}
context_menu_->PopupAsContext(gfx::Point(event->x_root, event->y_root),
event->time);
}
bool BrowserTitlebar::IsCommandIdEnabled(int command_id) const {
if (command_id == kShowWindowDecorationsCommand)
return true;
return chrome::IsCommandEnabled(browser_window_->browser(), command_id);
}
bool BrowserTitlebar::IsCommandIdChecked(int command_id) const {
if (command_id == kShowWindowDecorationsCommand) {
PrefService* prefs = browser_window_->browser()->profile()->GetPrefs();
return !prefs->GetBoolean(prefs::kUseCustomChromeFrame);
}
EncodingMenuController controller;
if (controller.DoesCommandBelongToEncodingMenu(command_id)) {
WebContents* web_contents =
browser_window_->browser()->tab_strip_model()->GetActiveWebContents();
if (web_contents) {
return controller.IsItemChecked(browser_window_->browser()->profile(),
web_contents->GetEncoding(),
command_id);
}
return false;
}
NOTREACHED();
return false;
}
void BrowserTitlebar::ExecuteCommand(int command_id, int event_flags) {
if (command_id == kShowWindowDecorationsCommand) {
PrefService* prefs = browser_window_->browser()->profile()->GetPrefs();
prefs->SetBoolean(prefs::kUseCustomChromeFrame,
!prefs->GetBoolean(prefs::kUseCustomChromeFrame));
return;
}
chrome::ExecuteCommand(browser_window_->browser(), command_id);
}
bool BrowserTitlebar::GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* out_accelerator) {
const ui::Accelerator* accelerator =
AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
command_id);
if (!accelerator)
return false;
*out_accelerator = *accelerator;
return true;
}
void BrowserTitlebar::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
UpdateTextColor();
UpdateAvatarLabel();
if (minimize_button_.get())
UpdateButtonBackground(minimize_button_.get());
if (maximize_button_.get())
UpdateButtonBackground(maximize_button_.get());
if (restore_button_.get())
UpdateButtonBackground(restore_button_.get());
if (close_button_.get())
UpdateButtonBackground(close_button_.get());
break;
}
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
if (!IsOffTheRecord())
UpdateAvatar();
break;
default:
NOTREACHED();
}
}
void BrowserTitlebar::ActiveWindowChanged(GdkWindow* active_window) {
if (!window_)
return;
window_has_focus_ =
gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
UpdateTextColor();
}
bool BrowserTitlebar::ShouldDisplayAvatar() {
if (IsOffTheRecord())
return true;
if (!browser_window_->browser()->is_type_tabbed())
return false;
return AvatarMenu::ShouldShowAvatarMenu();
}
bool BrowserTitlebar::IsOffTheRecord() {
return browser_window_->browser()->profile()->IsOffTheRecord();
}
BrowserTitlebar::ContextMenuModel::ContextMenuModel(
ui::SimpleMenuModel::Delegate* delegate)
: SimpleMenuModel(delegate) {
AddItemWithStringId(IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB);
AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB);
AddSeparator(ui::NORMAL_SEPARATOR);
AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
AddSeparator(ui::NORMAL_SEPARATOR);
AddCheckItemWithStringId(kShowWindowDecorationsCommand,
IDS_SHOW_WINDOW_DECORATIONS_MENU);
}