summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/browser_titlebar.cc
diff options
context:
space:
mode:
authorerg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-13 21:36:59 +0000
committererg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-13 21:36:59 +0000
commitcd1454e93e232cdbd0569f363d5020e6c750dc35 (patch)
tree07d623e5a86c67bbf42cc7b1d009d5acfcd84eab /chrome/browser/gtk/browser_titlebar.cc
parent0545571b0d2372be3c63664516a772a6a7700524 (diff)
downloadchromium_src-cd1454e93e232cdbd0569f363d5020e6c750dc35.zip
chromium_src-cd1454e93e232cdbd0569f363d5020e6c750dc35.tar.gz
chromium_src-cd1454e93e232cdbd0569f363d5020e6c750dc35.tar.bz2
GTK: Support Ambiance/Radiance and Dust button ordering.
When running under GNOME, read the gconf key that defines the button placement and lay the close, minimize and maximize buttons out. This can even handle bizarre combinations like putting the close button on the left and the minimize/maximize buttons on the right. When running under anything else, use the default button ordering. BUG=39406 TEST=none Review URL: http://codereview.chromium.org/2095001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47195 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk/browser_titlebar.cc')
-rw-r--r--chrome/browser/gtk/browser_titlebar.cc286
1 files changed, 207 insertions, 79 deletions
diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc
index f4ce056..7b9576f 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_);
}
}