summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-10 22:53:30 +0000
committertc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-10 22:53:30 +0000
commit47775b5ded90797ebc562a7407afcf41d849f60e (patch)
tree60ffa96a1a365e11754b13a2140add6f9fc2678c
parentd6834fa88a43fc077d380bc500c2d1d6a4ababaa (diff)
downloadchromium_src-47775b5ded90797ebc562a7407afcf41d849f60e.zip
chromium_src-47775b5ded90797ebc562a7407afcf41d849f60e.tar.gz
chromium_src-47775b5ded90797ebc562a7407afcf41d849f60e.tar.bz2
First cut at tall titlebar and custom window frame.
This implements the tall titlebar with the XP frame buttons, which should work if your window manager supports them. The titlebar background is drawn by the containing hbox. It would be nice if the tab strip could be made transparent so it wouldn't need to paint a background itself, but I didn't know how to do that. I still need to implement the frame resizing, frame coloring and move the context menu from the tab strip to the titlebar. BUG=13430 Review URL: http://codereview.chromium.org/119371 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18107 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc162
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h41
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc16
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h5
4 files changed, 196 insertions, 28 deletions
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index 076e84c..1ca20a7 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -7,6 +7,7 @@
#include <gdk/gdkkeysyms.h>
#include "app/resource_bundle.h"
+#include "app/l10n_util.h"
#include "base/base_paths_linux.h"
#include "base/gfx/gtk_util.h"
#include "base/logging.h"
@@ -24,11 +25,13 @@
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
#include "chrome/browser/gtk/browser_toolbar_gtk.h"
#include "chrome/browser/gtk/clear_browsing_data_dialog_gtk.h"
+#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/download_shelf_gtk.h"
#include "chrome/browser/gtk/go_button_gtk.h"
#include "chrome/browser/gtk/import_dialog_gtk.h"
#include "chrome/browser/gtk/infobar_container_gtk.h"
#include "chrome/browser/gtk/find_bar_gtk.h"
+#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/status_bubble_gtk.h"
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
@@ -40,6 +43,8 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
namespace {
@@ -51,6 +56,12 @@ const GdkColor kBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4);
const char* kBrowserWindowKey = "__BROWSER_WINDOW_GTK__";
+// The width of the custom frame.
+const int kCustomFrameWidth = 3;
+
+// The space above the titlebars.
+const int kTitlebarHeight = 14;
+
gboolean MainWindowConfigured(GtkWindow* window, GdkEventConfigure* event,
BrowserWindowGtk* browser_win) {
gfx::Rect bounds = gfx::Rect(event->x, event->y, event->width, event->height);
@@ -312,13 +323,27 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser)
ConnectAccelerators();
bounds_ = GetInitialWindowBounds(window_);
- // This vbox encompasses all of the widgets within the browser, including
- // the tabstrip and the content vbox.
- window_vbox_ = gtk_vbox_new(FALSE, 0);
+ titlebar_background_.reset(new NineBox(
+ browser_->profile()->GetThemeProvider(),
+ 0, IDR_THEME_FRAME, 0, 0, 0, 0, 0, 0, 0));
+ titlebar_background_otr_.reset(new NineBox(
+ browser_->profile()->GetThemeProvider(),
+ 0, IDR_THEME_FRAME_INCOGNITO, 0, 0, 0, 0, 0, 0, 0));
- tabstrip_.reset(new TabStripGtk(browser_->tabstrip_model()));
- tabstrip_->Init(bounds_.width(), browser_->profile());
- tabstrip_->AddTabStripToBox(window_vbox_);
+ // This vbox encompasses all of the widgets within the browser, including the
+ // tabstrip and the content vbox. The vbox is put in a floating container
+ // (see gtk_floating_container.h) so we can position the
+ // minimize/maximize/close buttons. The floating container is then put in an
+ // alignment so we can do custom frame drawing if the user turns of window
+ // manager decorations.
+ GtkWidget* window_vbox = gtk_vbox_new(FALSE, 0);
+ gtk_widget_show(window_vbox);
+
+ window_container_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
+ gtk_container_add(GTK_CONTAINER(window_container_), window_vbox);
+
+ // Build the titlebar (tabstrip + header space + min/max/close buttons).
+ BuildTitlebar(window_vbox);
// The content_vbox_ surrounds the "content": toolbar+bookmarks bar+page.
content_vbox_ = gtk_vbox_new(FALSE, 0);
@@ -360,9 +385,9 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser)
gtk_container_add(GTK_CONTAINER(event_box), render_area_vbox_);
gtk_widget_show(event_box);
gtk_container_add(GTK_CONTAINER(content_vbox_), event_box);
- gtk_container_add(GTK_CONTAINER(window_vbox_), content_vbox_);
- gtk_container_add(GTK_CONTAINER(window_), window_vbox_);
- gtk_widget_show(window_vbox_);
+ gtk_container_add(GTK_CONTAINER(window_vbox), content_vbox_);
+ gtk_container_add(GTK_CONTAINER(window_), window_container_);
+ gtk_widget_show(window_container_);
browser_->tabstrip_model()->AddObserver(this);
HideUnsupportedWindowFeatures();
@@ -394,6 +419,34 @@ gboolean BrowserWindowGtk::OnContentAreaExpose(GtkWidget* widget,
return FALSE; // Allow subwidgets to paint.
}
+gboolean BrowserWindowGtk::OnTitlebarExpose(GtkWidget* widget,
+ GdkEventExpose* e,
+ BrowserWindowGtk* window) {
+ cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+ cairo_rectangle(cr, e->area.x, e->area.y, e->area.width, e->area.height);
+ cairo_clip(cr);
+ NineBox* image = window->browser_->profile()->IsOffTheRecord()
+ ? window->titlebar_background_otr_.get()
+ : window->titlebar_background_.get();
+ image->RenderTopCenterStrip(cr, e->area.x, e->area.y, e->area.width);
+ cairo_destroy(cr);
+
+ return FALSE; // Allow subwidgets to paint.
+}
+
+void BrowserWindowGtk::OnButtonClicked(GtkWidget* button,
+ BrowserWindowGtk* window) {
+ if (window->close_button_->widget() == button) {
+ window->Close();
+ } else if (window->restore_button_->widget() == button) {
+ gtk_window_unmaximize(window->window_);
+ } else if (window->maximize_button_->widget() == button) {
+ gtk_window_maximize(window->window_);
+ } else if (window->minimize_button_->widget() == button) {
+ gtk_window_iconify(window->window_);
+ }
+}
+
void BrowserWindowGtk::Show() {
gtk_widget_show(GTK_WIDGET(window_));
}
@@ -735,6 +788,16 @@ void BrowserWindowGtk::OnBoundsChanged(const gfx::Rect& bounds) {
void BrowserWindowGtk::OnStateChanged(GdkWindowState state) {
state_ = state;
+
+ // Update the maximize/restore button.
+ if (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());
+ }
+
SaveWindowPosition();
}
@@ -840,15 +903,88 @@ void BrowserWindowGtk::ConnectAccelerators() {
}
}
+void BrowserWindowGtk::BuildTitlebar(GtkWidget* container) {
+ // +- HBox (titlebar_hbox) -----------------------------------------------+
+ // |+- Alignment (titlebar_alignment_)-++- VBox (titlebar_buttons_box_) -+|
+ // || ||+- HBox -----------------------+||
+ // || |||+- button -++- button -+ |||
+ // ||+- TabStripGtk ------------------+|||| minimize || restore | ... |||
+ // ||| tab tab tab tabclose +|||+----------++----------+ |||
+ // ||+--------------------------------+||+------------------------------+||
+ // |+----------------------------------++--------------------------------+|
+ // +----------------------------------------------------------------------+
+ //
+ GtkWidget* titlebar_hbox = gtk_hbox_new(FALSE, 0);
+ g_signal_connect(G_OBJECT(titlebar_hbox), "expose-event",
+ G_CALLBACK(&OnTitlebarExpose), this);
+
+ // We use an alignment to control the titlebar height.
+ titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
+ gtk_box_pack_start(GTK_BOX(titlebar_hbox), titlebar_alignment_, TRUE,
+ TRUE, 0);
+
+ tabstrip_.reset(new TabStripGtk(browser_->tabstrip_model()));
+ tabstrip_->Init(browser_->profile());
+ gtk_container_add(GTK_CONTAINER(titlebar_alignment_), tabstrip_->widget());
+
+ // We put the min/max/restore/close buttons in a vbox so they are top aligned
+ // and don't vertically stretch.
+ titlebar_buttons_box_ = gtk_vbox_new(FALSE, 0);
+ GtkWidget* buttons_hbox = gtk_hbox_new(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_box_pack_end(GTK_BOX(titlebar_hbox), titlebar_buttons_box_, FALSE,
+ FALSE, 0);
+
+ gtk_widget_show_all(titlebar_hbox);
+ if (IsMaximized()) {
+ gtk_widget_hide(maximize_button_->widget());
+ } else {
+ gtk_widget_hide(restore_button_->widget());
+ }
+
+ gtk_box_pack_start(GTK_BOX(container), titlebar_hbox, FALSE, FALSE, 0);
+}
+
+CustomDrawButton* BrowserWindowGtk::BuildTitlebarButton(int image,
+ int image_pressed, int image_hot, GtkWidget* box, int tooltip) {
+ CustomDrawButton* button = new CustomDrawButton(image, image_pressed,
+ image_hot, 0);
+ g_signal_connect(button->widget(), "clicked", G_CALLBACK(OnButtonClicked),
+ this);
+ 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);
+ return button;
+}
+
void BrowserWindowGtk::UpdateCustomFrame() {
gtk_window_set_decorated(window_,
!use_custom_frame_.GetValue());
if (use_custom_frame_.GetValue()) {
- // TODO(port): The taller title bar and custom window border.
- gtk_container_set_border_width(GTK_CONTAINER(window_vbox_), 0);
- NOTIMPLEMENTED();
+ gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 0,
+ kCustomFrameWidth, kCustomFrameWidth, kCustomFrameWidth);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
+ kTitlebarHeight, 0, 0, 0);
+ gtk_widget_show_all(titlebar_buttons_box_);
} else {
- gtk_container_set_border_width(GTK_CONTAINER(window_vbox_), 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 0, 0, 0, 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_), 0, 0, 0, 0);
+ gtk_widget_hide(titlebar_buttons_box_);
}
}
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index 73285f2..c253832 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -20,6 +20,7 @@
class BookmarkBarGtk;
class BrowserToolbarGtk;
+class CustomDrawButton;
class DownloadShelfGtk;
class FindBarGtk;
class InfoBarContainerGtk;
@@ -135,8 +136,14 @@ class BrowserWindowGtk : public BrowserWindow,
virtual void DestroyBrowser();
// Top level window.
GtkWindow* window_;
- // VBox that holds the interior components of the chromium window.
- GtkWidget* window_vbox_;
+ // GtkAlignment that holds the interior components of the chromium window.
+ GtkWidget* window_container_;
+ // Box that holds the min/max/close buttons if the user turns off window
+ // manager decorations.
+ GtkWidget* titlebar_buttons_box_;
+ // Gtk alignment that contains the tab strip. If the user turns off window
+ // manager decorations, we draw this taller.
+ GtkWidget* titlebar_alignment_;
// VBox that holds everything below the tabs.
GtkWidget* content_vbox_;
// VBox that holds everything below the toolbar.
@@ -159,6 +166,17 @@ class BrowserWindowGtk : public BrowserWindow,
// ctrl-l, etc.).
void ConnectAccelerators();
+ // Build the titlebar which includes the tab strip, the space above the tab
+ // strip, and (maybe) the min, max, close buttons. |container| is the gtk
+ // continer that we put the widget into.
+ void BuildTitlebar(GtkWidget* container);
+
+ // Constructs a CustomDraw button given 3 image ids (IDR_), the box to place
+ // the button into, and a tooltip id (IDS_).
+ CustomDrawButton* BuildTitlebarButton(int image, int image_pressed,
+ int image_hot, GtkWidget* box,
+ int tooltip);
+
// Change whether we're showing the custom blue frame.
// Must be called once at startup.
// Triggers relayout of the content.
@@ -169,10 +187,17 @@ class BrowserWindowGtk : public BrowserWindow,
// Callback for when the "content area" vbox needs to be redrawn.
// The content area includes the toolbar and web page but not the tab strip.
- // It has a soft gray border when we have a custom frame.
static gboolean OnContentAreaExpose(GtkWidget* widget, GdkEventExpose* e,
BrowserWindowGtk* window);
+ // Callback for when the titlebar (include the background of the tab strip)
+ // needs to be redrawn.
+ static gboolean OnTitlebarExpose(GtkWidget* widget, GdkEventExpose* e,
+ BrowserWindowGtk* window);
+
+ // Callback for min/max/close buttons.
+ static void OnButtonClicked(GtkWidget* button, BrowserWindowGtk* window);
+
static gboolean OnGtkAccelerator(GtkAccelGroup* accel_group,
GObject* acceleratable,
guint keyval,
@@ -228,6 +253,16 @@ class BrowserWindowGtk : public BrowserWindow,
// The container for info bars. Always non-NULL.
scoped_ptr<InfoBarContainerGtk> infobar_container_;
+ // Maximize and restore widgets in the titlebar.
+ scoped_ptr<CustomDrawButton> minimize_button_;
+ scoped_ptr<CustomDrawButton> maximize_button_;
+ scoped_ptr<CustomDrawButton> restore_button_;
+ scoped_ptr<CustomDrawButton> close_button_;
+
+ // The background of the title bar and tab strip.
+ scoped_ptr<NineBox> titlebar_background_;
+ scoped_ptr<NineBox> titlebar_background_otr_;
+
// The timer used to update frames for the Loading Animation.
base::RepeatingTimer<BrowserWindowGtk> loading_animation_timer_;
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
index 38f610b..ab6e88c 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
@@ -475,7 +475,7 @@ TabStripGtk::~TabStripGtk() {
tab_data_.clear();
}
-void TabStripGtk::Init(int width, Profile* profile) {
+void TabStripGtk::Init(Profile* profile) {
ThemeProvider* theme_provider = profile->GetThemeProvider();
model_->AddObserver(this);
@@ -486,7 +486,7 @@ void TabStripGtk::Init(int width, Profile* profile) {
tabstrip_.Own(gtk_fixed_new());
gtk_fixed_set_has_window(GTK_FIXED(tabstrip_.get()), TRUE);
- gtk_widget_set_size_request(tabstrip_.get(), width,
+ gtk_widget_set_size_request(tabstrip_.get(), -1,
TabGtk::GetMinimumUnselectedSize().height());
gtk_widget_set_app_paintable(tabstrip_.get(), TRUE);
gtk_drag_dest_set(tabstrip_.get(), GTK_DEST_DEFAULT_ALL,
@@ -520,10 +520,6 @@ void TabStripGtk::Init(int width, Profile* profile) {
}
}
-void TabStripGtk::AddTabStripToBox(GtkWidget* box) {
- gtk_box_pack_start(GTK_BOX(box), tabstrip_.get(), FALSE, FALSE, 0);
-}
-
void TabStripGtk::Show() {
gtk_widget_show(tabstrip_.get());
}
@@ -1330,7 +1326,7 @@ gboolean TabStripGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event,
event->area.height = tabstrip->bounds_.height();
gdk_region_union_with_rect(event->region, &event->area);
- tabstrip->PaintBackground(event);
+ tabstrip->PaintBackground(widget, event);
// Paint the New Tab button.
gtk_container_propagate_expose(GTK_CONTAINER(tabstrip->tabstrip_.get()),
@@ -1455,9 +1451,11 @@ void TabStripGtk::OnNewTabClicked(GtkWidget* widget, TabStripGtk* tabstrip) {
tabstrip->model_->delegate()->AddBlankTab(true);
}
-void TabStripGtk::PaintBackground(GdkEventExpose* event) {
+void TabStripGtk::PaintBackground(GtkWidget* widget, GdkEventExpose* event) {
gfx::CanvasPaint canvas(event);
- canvas.TileImageInt(*background_, 0, 0, bounds_.width(), bounds_.height());
+ // Offset the background by the height of the titlebar.
+ canvas.TileImageInt(*background_, 0, widget->allocation.y, 0, 0,
+ bounds_.width(), bounds_.height());
}
void TabStripGtk::SetTabBounds(TabGtk* tab, const gfx::Rect& bounds) {
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h
index ddb79b0..7c21073 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h
@@ -31,8 +31,7 @@ class TabStripGtk : public TabStripModelObserver,
// TODO(jhawkins): We have to pass in |profile| in order to get a pointer to
// the theme provider. In views, all instances of views::View have access to
// the theme provider.
- void Init(int width, Profile* profile);
- void AddTabStripToBox(GtkWidget* box);
+ void Init(Profile* profile);
void Show();
void Hide();
@@ -203,7 +202,7 @@ class TabStripGtk : public TabStripModelObserver,
static void OnNewTabClicked(GtkWidget* widget, TabStripGtk* tabstrip);
// Renders the tabstrip background.
- void PaintBackground(GdkEventExpose* event);
+ void PaintBackground(GtkWidget* widget, GdkEventExpose* event);
// Sets the bounds of the tab and moves the tab widget to those bounds.
void SetTabBounds(TabGtk* tab, const gfx::Rect& bounds);