| Index: chrome/browser/gtk/browser_titlebar.cc
|
| diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc
|
| index f4ce05662e0ca97a91e3a97daedde41ea968f6fc..7b9576ffcb05f46ebf8940f2d343f57cde6b1ca0 100644
|
| --- a/chrome/browser/gtk/browser_titlebar.cc
|
| +++ b/chrome/browser/gtk/browser_titlebar.cc
|
| @@ -14,12 +14,15 @@
|
| #include "app/resource_bundle.h"
|
| #include "base/command_line.h"
|
| #include "base/singleton.h"
|
| +#include "base/string_piece.h"
|
| +#include "base/string_tokenizer.h"
|
| #include "chrome/app/chrome_dll_resource.h"
|
| #include "chrome/browser/browser.h"
|
| #include "chrome/browser/encoding_menu_controller.h"
|
| #include "chrome/browser/gtk/accelerators_gtk.h"
|
| #include "chrome/browser/gtk/browser_window_gtk.h"
|
| #include "chrome/browser/gtk/custom_button.h"
|
| +#include "chrome/browser/gtk/gconf_titlebar_listener.h"
|
| #include "chrome/browser/gtk/gtk_theme_provider.h"
|
| #include "chrome/browser/gtk/gtk_util.h"
|
| #include "chrome/browser/gtk/menu_gtk.h"
|
| @@ -128,7 +131,14 @@ GdkColor PickLuminosityContrastingColor(const GdkColor* base,
|
|
|
| BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window,
|
| GtkWindow* window)
|
| - : browser_window_(browser_window), window_(window),
|
| + : browser_window_(browser_window),
|
| + window_(window),
|
| + titlebar_left_buttons_vbox_(NULL),
|
| + titlebar_right_buttons_vbox_(NULL),
|
| + titlebar_left_buttons_hbox_(NULL),
|
| + titlebar_right_buttons_hbox_(NULL),
|
| + top_padding_left_(NULL),
|
| + top_padding_right_(NULL),
|
| app_mode_favicon_(NULL),
|
| app_mode_title_(NULL),
|
| using_custom_frame_(false),
|
| @@ -140,17 +150,37 @@ BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window,
|
| void BrowserTitlebar::Init() {
|
| // The widget hierarchy is shown below.
|
| //
|
| - // +- EventBox (container_) -------------------------------------------------+
|
| - // +- HBox (container_hbox) -------------------------------------------------+
|
| - // |+- Algn. -++- Alignment --------------++- VBox (titlebar_buttons_box_) -+|
|
| - // ||+ Image +|| (titlebar_alignment_) ||+ - Fixed (top_padding_) ------+||
|
| - // ||| ||| ||+- HBox -----------------------+||
|
| - // |||spy_guy||| |||+- button -++- button -+ |||
|
| - // ||| |||+- TabStripGtk ---------+|||| minimize || restore | ... |||
|
| - // ||| )8\ |||| tab tab tabclose ||||+----------++----------+ |||
|
| - // ||+-------+||+------------------------+||+------------------------------+||
|
| - // |+---------++--------------------------++--------------------------------+|
|
| - // +-------------------------------------------------------------------------+
|
| + // +- EventBox (container_) -------------------------------------+
|
| + // +- HBox (container_hbox_) ------------------------------------+
|
| + // |+ VBox ---++- Algn. -++- Alignment --------------++ VBox ---+|
|
| + // || titlebar||+ Image +|| (titlebar_alignment_) || titlebar||
|
| + // || left ||| ||| || right ||
|
| + // || button |||spy_guy||| || button ||
|
| + // || vbox ||| |||+- TabStripGtk ---------+|| vbox ||
|
| + // || ||| )8\ |||| tab tab tabclose ||| ||
|
| + // || ||+-------+||+------------------------+|| ||
|
| + // |+---------++---------++--------------------------++---------+|
|
| + // +-------------------------------------------------------------+
|
| + //
|
| + // There are two vboxes on either side of |container_hbox_| because when the
|
| + // desktop is GNOME, the button placement is configurable based on a metacity
|
| + // gconf key. We can't just have one vbox and move it back and forth because
|
| + // the gconf language allows you to place buttons on both sides of the
|
| + // window. This being Linux, I'm sure there's a bunch of people who have
|
| + // already configured their window manager to do so and we don't want to get
|
| + // confused when that happens. The actual contents of these vboxes are lazily
|
| + // generated so they don't interfere with alignment when everything is
|
| + // stuffed in the other box.
|
| + //
|
| + // Each vbox has the contains the following hierarchy if it contains buttons:
|
| + //
|
| + // +- VBox (titlebar_{l,r}_buttons_vbox_) ---------+
|
| + // |+- Fixed (top_padding_{l,r}_) ----------------+|
|
| + // ||+- HBox (titlebar_{l,r}_buttons_hbox_ ------+||
|
| + // ||| (buttons of a configurable layout) |||
|
| + // ||+-------------------------------------------+||
|
| + // |+---------------------------------------------+|
|
| + // +-----------------------------------------------+
|
| //
|
| // If we're a popup window or in app mode, we don't display the spy guy or
|
| // the tab strip. Instead, put an hbox in titlebar_alignment_ in place of
|
| @@ -163,18 +193,30 @@ void BrowserTitlebar::Init() {
|
| // ||+---------------++------------------------++----------------------+||
|
| // |+-------------------------------------------------------------------+|
|
| // +---------------------------------------------------------------------+
|
| - GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0);
|
| + 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);
|
| + gtk_container_add(GTK_CONTAINER(container_), container_hbox_);
|
|
|
| g_signal_connect(container_, "scroll-event", G_CALLBACK(OnScroll), this);
|
|
|
| g_signal_connect(window_, "window-state-event",
|
| G_CALLBACK(OnWindowStateChanged), this);
|
|
|
| + // Allocate the two button boxes on the left and right parts of the bar.
|
| + 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_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
|
| + gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_buttons_vbox_,
|
| + FALSE, FALSE, 0);
|
| +
|
| + // Either read the gconf database and register for updates (on GNOME), or use
|
| + // the default value (anywhere else).
|
| + Singleton<GConfTitlebarListener>()->SetTitlebarButtons(this);
|
| +
|
| if (browser_window_->browser()->profile()->IsOffTheRecord() &&
|
| browser_window_->browser()->type() == Browser::TYPE_NORMAL) {
|
| GtkWidget* spy_guy = gtk_image_new_from_pixbuf(GetOTRAvatar());
|
| @@ -186,13 +228,13 @@ void BrowserTitlebar::Init() {
|
| kOTRBottomSpacing, kOTRSideSpacing, kOTRSideSpacing);
|
| gtk_widget_set_size_request(spy_guy, -1, 0);
|
| gtk_container_add(GTK_CONTAINER(spy_frame), spy_guy);
|
| - gtk_box_pack_start(GTK_BOX(container_hbox), spy_frame, FALSE, FALSE, 0);
|
| + gtk_box_pack_start(GTK_BOX(container_hbox_), spy_frame, FALSE, FALSE, 0);
|
| }
|
|
|
| // We use an alignment to control the titlebar height.
|
| titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
|
| if (browser_window_->browser()->type() == Browser::TYPE_NORMAL) {
|
| - gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE,
|
| + gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE,
|
| TRUE, 0);
|
|
|
| // Put the tab strip in the titlebar.
|
| @@ -200,7 +242,7 @@ void BrowserTitlebar::Init() {
|
| browser_window_->tabstrip()->widget());
|
| } else {
|
| // App mode specific widgets.
|
| - gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE,
|
| + 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);
|
| @@ -242,41 +284,6 @@ void BrowserTitlebar::Init() {
|
| UpdateTitleAndIcon();
|
| }
|
|
|
| - // We put the min/max/restore/close buttons in a vbox so they are top aligned
|
| - // (up to padding) and don't vertically stretch.
|
| - titlebar_buttons_box_ = gtk_vbox_new(FALSE, 0);
|
| - GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing);
|
| - top_padding_ = gtk_fixed_new();
|
| - gtk_widget_set_size_request(top_padding_, -1, kButtonOuterPadding);
|
| - gtk_box_pack_start(GTK_BOX(titlebar_buttons_box_), top_padding_, FALSE, FALSE,
|
| - 0);
|
| - gtk_box_pack_start(GTK_BOX(titlebar_buttons_box_), buttons_hbox, FALSE,
|
| - FALSE, 0);
|
| -
|
| - close_button_.reset(BuildTitlebarButton(IDR_CLOSE, IDR_CLOSE_P, IDR_CLOSE_H,
|
| - buttons_hbox,
|
| - IDS_XPFRAME_CLOSE_TOOLTIP));
|
| -
|
| - restore_button_.reset(BuildTitlebarButton(IDR_RESTORE, IDR_RESTORE_P,
|
| - IDR_RESTORE_H, buttons_hbox,
|
| - IDS_XPFRAME_RESTORE_TOOLTIP));
|
| - maximize_button_.reset(BuildTitlebarButton(IDR_MAXIMIZE, IDR_MAXIMIZE_P,
|
| - IDR_MAXIMIZE_H, buttons_hbox,
|
| - IDS_XPFRAME_MAXIMIZE_TOOLTIP));
|
| - minimize_button_.reset(BuildTitlebarButton(IDR_MINIMIZE, IDR_MINIMIZE_P,
|
| - IDR_MINIMIZE_H, buttons_hbox,
|
| - IDS_XPFRAME_MINIMIZE_TOOLTIP));
|
| -
|
| - gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(),
|
| - true, true, true);
|
| -
|
| - gtk_widget_size_request(close_button_->widget(), &close_button_req_);
|
| - gtk_widget_size_request(minimize_button_->widget(), &minimize_button_req_);
|
| - gtk_widget_size_request(restore_button_->widget(), &restore_button_req_);
|
| -
|
| - gtk_box_pack_end(GTK_BOX(container_hbox), titlebar_buttons_box_, FALSE,
|
| - FALSE, 0);
|
| -
|
| gtk_widget_show_all(container_);
|
|
|
| ActiveWindowWatcherX::AddObserver(this);
|
| @@ -284,6 +291,102 @@ void BrowserTitlebar::Init() {
|
|
|
| BrowserTitlebar::~BrowserTitlebar() {
|
| ActiveWindowWatcherX::RemoveObserver(this);
|
| + Singleton<GConfTitlebarListener>()->RemoveObserver(this);
|
| +}
|
| +
|
| +void BrowserTitlebar::BuildButtons(const std::string& button_string) {
|
| + // Clear out all previous data.
|
| + 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;
|
| + StringTokenizer tokenizer(button_string, ":,");
|
| + tokenizer.set_options(StringTokenizer::RETURN_DELIMS);
|
| + while (tokenizer.GetNext()) {
|
| + if (tokenizer.token_is_delim()) {
|
| + if (*tokenizer.token_begin() == ':')
|
| + left_side = false;
|
| + } else {
|
| + base::StringPiece token = tokenizer.token_piece();
|
| + if (token == "minimize") {
|
| + GtkWidget* parent_box = GetButtonHBox(left_side);
|
| + minimize_button_.reset(
|
| + BuildTitlebarButton(IDR_MINIMIZE, IDR_MINIMIZE_P,
|
| + IDR_MINIMIZE_H, parent_box,
|
| + IDS_XPFRAME_MINIMIZE_TOOLTIP));
|
| +
|
| + gtk_widget_size_request(minimize_button_->widget(),
|
| + &minimize_button_req_);
|
| + } else if (token == "maximize") {
|
| + GtkWidget* parent_box = GetButtonHBox(left_side);
|
| + restore_button_.reset(
|
| + BuildTitlebarButton(IDR_RESTORE, IDR_RESTORE_P,
|
| + IDR_RESTORE_H, parent_box,
|
| + IDS_XPFRAME_RESTORE_TOOLTIP));
|
| + maximize_button_.reset(
|
| + BuildTitlebarButton(IDR_MAXIMIZE, IDR_MAXIMIZE_P,
|
| + IDR_MAXIMIZE_H, parent_box,
|
| + IDS_XPFRAME_MAXIMIZE_TOOLTIP));
|
| +
|
| + gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(),
|
| + true, true, true);
|
| + gtk_widget_size_request(restore_button_->widget(),
|
| + &restore_button_req_);
|
| + } else if (token == "close") {
|
| + GtkWidget* parent_box = GetButtonHBox(left_side);
|
| + close_button_.reset(
|
| + BuildTitlebarButton(IDR_CLOSE, IDR_CLOSE_P,
|
| + IDR_CLOSE_H, parent_box,
|
| + IDS_XPFRAME_CLOSE_TOOLTIP));
|
| +
|
| + gtk_widget_size_request(close_button_->widget(), &close_button_req_);
|
| + }
|
| + // Ignore any other values like "pin" since we don't have images for
|
| + // those.
|
| + }
|
| + }
|
| +
|
| + // Now show the correct widgets in the two hierarchies.
|
| + gtk_widget_show_all(titlebar_left_buttons_vbox_);
|
| + gtk_widget_show_all(titlebar_right_buttons_vbox_);
|
| + UpdateMaximizeRestoreVisibility();
|
| +}
|
| +
|
| +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_;
|
| +
|
| + // We put the min/max/restore/close buttons in a vbox so they are top aligned
|
| + // (up to padding) and don't vertically stretch.
|
| + 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::BuildTitlebarButton(int image,
|
| @@ -298,16 +401,23 @@ CustomDrawButton* BrowserTitlebar::BuildTitlebarButton(int image,
|
| std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip);
|
| gtk_widget_set_tooltip_text(button->widget(),
|
| localized_tooltip.c_str());
|
| - gtk_box_pack_end(GTK_BOX(box), button->widget(), FALSE, FALSE, 0);
|
| + gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0);
|
| return button;
|
| }
|
|
|
| void BrowserTitlebar::UpdateCustomFrame(bool use_custom_frame) {
|
| using_custom_frame_ = use_custom_frame;
|
| - if (use_custom_frame)
|
| - gtk_widget_show(titlebar_buttons_box_);
|
| - else
|
| - gtk_widget_hide(titlebar_buttons_box_);
|
| + if (use_custom_frame) {
|
| + if (titlebar_left_buttons_vbox_)
|
| + gtk_widget_show(titlebar_left_buttons_vbox_);
|
| + if (titlebar_right_buttons_vbox_)
|
| + gtk_widget_show(titlebar_right_buttons_vbox_);
|
| + } else {
|
| + if (titlebar_left_buttons_vbox_)
|
| + gtk_widget_hide(titlebar_left_buttons_vbox_);
|
| + if (titlebar_right_buttons_vbox_)
|
| + gtk_widget_hide(titlebar_right_buttons_vbox_);
|
| + }
|
| UpdateTitlebarAlignment();
|
| }
|
|
|
| @@ -405,18 +515,31 @@ void BrowserTitlebar::UpdateTitlebarAlignment() {
|
| close_button_req.height += kButtonOuterPadding;
|
| minimize_button_req.height += kButtonOuterPadding;
|
| restore_button_req.height += kButtonOuterPadding;
|
| - gtk_widget_hide(top_padding_);
|
| + if (top_padding_left_)
|
| + gtk_widget_hide(top_padding_left_);
|
| + if (top_padding_right_)
|
| + gtk_widget_hide(top_padding_right_);
|
| } else {
|
| - gtk_widget_show(top_padding_);
|
| + 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);
|
| }
|
| - gtk_widget_set_size_request(close_button_->widget(),
|
| - close_button_req.width, close_button_req.height);
|
| - gtk_widget_set_size_request(minimize_button_->widget(),
|
| - minimize_button_req.width,
|
| - minimize_button_req.height);
|
| - gtk_widget_set_size_request(restore_button_->widget(),
|
| - restore_button_req.width,
|
| - restore_button_req.height);
|
| }
|
|
|
| void BrowserTitlebar::UpdateTextColor() {
|
| @@ -495,17 +618,22 @@ void BrowserTitlebar::MaximizeButtonClicked() {
|
| 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());
|
| + }
|
| + }
|
| +}
|
| +
|
| // static
|
| gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window,
|
| GdkEventWindowState* event, BrowserTitlebar* titlebar) {
|
| - // Update the maximize/restore button.
|
| - if (titlebar->browser_window_->IsMaximized()) {
|
| - gtk_widget_hide(titlebar->maximize_button_->widget());
|
| - gtk_widget_show(titlebar->restore_button_->widget());
|
| - } else {
|
| - gtk_widget_hide(titlebar->restore_button_->widget());
|
| - gtk_widget_show(titlebar->maximize_button_->widget());
|
| - }
|
| + titlebar->UpdateMaximizeRestoreVisibility();
|
| titlebar->UpdateTitlebarAlignment();
|
| titlebar->UpdateTextColor();
|
| return FALSE;
|
| @@ -529,13 +657,13 @@ gboolean BrowserTitlebar::OnScroll(GtkWidget* widget, GdkEventScroll* event,
|
|
|
| // static
|
| void BrowserTitlebar::OnButtonClicked(GtkWidget* button) {
|
| - if (close_button_->widget() == button) {
|
| + if (close_button_.get() && close_button_->widget() == button) {
|
| browser_window_->Close();
|
| - } else if (restore_button_->widget() == button) {
|
| + } else if (restore_button_.get() && restore_button_->widget() == button) {
|
| browser_window_->UnMaximize();
|
| - } else if (maximize_button_->widget() == button) {
|
| + } else if (maximize_button_.get() && maximize_button_->widget() == button) {
|
| MaximizeButtonClicked();
|
| - } else if (minimize_button_->widget() == button) {
|
| + } else if (minimize_button_.get() && minimize_button_->widget() == button) {
|
| gtk_window_iconify(window_);
|
| }
|
| }
|
|
|